void blur_gauss_xy(u64 size,u64 radius,u8* src,u8* dst) { int x,y; int m,n; int width,height; double sigma; double temp; double r,g,b; //由公式:d = 6σ + 1,可以得到σ = r / 3. if(radius>9)radius=9; sigma=(double)radius; sigma/=3; //say("radius=%lld,sigma=%lf\n",radius,sigma); //first build the "gauss table" for(y=0;y<=radius;y++) { temp = (double)(-y*y); temp /= 2*sigma*sigma; gausstable[0][y] = exponent(temp); gausstable[0][y] /= sigma*squareroot(2*pi); //say("gausstable[%d]=%lf\n",y,gausstable[0][y]); } //开始(x) width=size&0xffff; height=(size>>16)&0xffff; for(y=radius;y<height-radius;y++) { for(x=radius;x<width-radius;x++) { //process this pixel r=g=b=0.0; //<0 for(m=-radius;m<0;m++) { // temp=gausstable[0][-m]; //b b+=temp*(double)src[ ( (width*y + x+m )<<2)+0]; //g g+=temp*(double)src[ ( (width*y + x+m )<<2)+1]; //r r+=temp*(double)src[ ( (width*y + x+m )<<2)+2]; }//m //>0 for(m=0;m<radius;m++) { // temp=gausstable[0][m]; //b b+=temp*(double)src[ ( (width*y + x+m )<<2)+0]; //g g+=temp*(double)src[ ( (width*y + x+m )<<2)+1]; //r r+=temp*(double)src[ ( (width*y + x+m )<<2)+2]; }//m //<0 for(m=-radius;m<0;m++) { // temp=gausstable[0][-m]; //b b+=temp*(double)src[ ( (width*(y+m) + x )<<2)+0]; //g g+=temp*(double)src[ ( (width*(y+m) + x )<<2)+1]; //r r+=temp*(double)src[ ( (width*(y+m) + x )<<2)+2]; }//m //>0 for(m=0;m<radius;m++) { // temp=gausstable[0][m]; //b b+=temp*(double)src[ ( (width*(y+m) + x )<<2)+0]; //g g+=temp*(double)src[ ( (width*(y+m) + x )<<2)+1]; //r r+=temp*(double)src[ ( (width*(y+m) + x )<<2)+2]; }//m //put the result //say("(%d,%d):%lf,%lf,%lf\n",x,y,b,g,r); dst[((width*y+x)<<2)+0]=(int)(b/2); dst[((width*y+x)<<2)+1]=(int)(g/2); dst[((width*y+x)<<2)+2]=(int)(r/2); }//x }//y }
TEST(SquareRootTest, PositiveNos) { EXPECT_EQ (18.0, squareroot (324.0)); EXPECT_EQ (25.4, squareroot (645.16)); EXPECT_EQ (50.332, squareroot (2533.310224)); }
void amergesort(void *base, size_t nmemb, size_t size, cmpfn compare CTXPARAM) { size_t bufsize = 0; /* * Stupid special case: sorting zero elements should just * return rather than go mad. */ if (nmemb == 0) return; /* * Start by extracting a buffer of size 3*sqrt(n), or as large * as we can get short of that. * * The buffer will end up at the start of the array, but the * buffer extraction procedure cannot involve _swapping_ * elements into that area, because moving an element past * other elements it hasn't been compared with would risk * destroying stability. So instead, we move the buffer * gradually up the array as we go, and move it back down when * we've finished. * * Since we're extracting the buffer once for the entire sort, * we're allowed to do O(N log N) work to get it if we need * to. (Good job too, since the fact that the list is unsorted * at this stage would make it tricky otherwise.) * * Special case: if the entire list is small enough that we're * never going to need a Symvonis algorithm at all, we needn't * bother and we can just leave bufsize at zero. */ if (nmemb > RECURSION_THRESHOLD) { size_t bufsize_preferred = 3 * squareroot(nmemb); size_t buftop = 1, currpos = 1; bufsize = 1; while (currpos < nmemb && bufsize < bufsize_preferred) { /* * See if the next array element is equal to anything * in the buffer. We can safely do a log-time binary * search of the buffer to check this. */ size_t bufbot = buftop - bufsize; size_t bot = buftop - bufsize - 1, top = buftop, mid; int cmp; while (top - bot > 1) { mid = (top + bot) / 2; cmp = COMPARE(currpos, mid); if (cmp == 0) { currpos++; goto buf_extract_continue; /* order-2 "continue" */ } else if (cmp < 0) top = mid; else bot = mid; } /* * If we get here, then the new element can indeed go * in the buffer, and moreover "top" points at exactly * where it needs to be. * * So we have a chunk of array that looks like * * bufbot top buftop currpos * +------+-------+------------+-+ * | A | B | C |X| * +------+-------+------------+-+ * * which we want to rearrange so that it looks like * +------------+------+-+-------+ * | C | A |X| B | * +------------+------+-+-------+ * * To achieve this, we do a block exchange of AB with * C to get this intermediate stage: * +------------+------+-------+-+ * | C | A | B |X| * +------------+------+-------+-+ * * followed by a nearly trivial block exchange of B * with X. * * Elements that don't end up in the buffer (i.e. * things in C) are only ever moved once by one of * these procedures, so there are O(N) such moves in * total. Elements that do end up in the buffer are * moved once for every subsequent buffer element * added, so there are O(bufsize^2) such moves - but * bufsize itself is O(sqrt(N)), so this is O(N) time * in total as well. */ block_exchange(base, size, bufbot, bufsize, currpos - buftop); block_exchange(base, size, currpos - (buftop-top), buftop-top, 1); buftop = ++currpos; bufsize++; #ifdef TESTMODE subseq_should_be_sorted(buftop - bufsize, bufsize); #endif buf_extract_continue:; } /* * Now we've got our complete buffer, move it back down to * the bottom of the array. */ block_exchange(base, size, 0, buftop - bufsize, bufsize); #ifdef TESTMODE subseq_should_be_sorted(0, bufsize); #endif } /* * Special case: if we only managed to get _one_ buffer * element, then that must mean absolutely all elements in the * array compare equal. Hence, no sorting required; just * return. */ if (bufsize == 1) return; /* * Now we can do the main sort. We start with simple insertion * sorts (which are stable) for small subarrays, and then use * stable merging algorithms to merge those subarrays * gradually up into a whole sorted array. (Well, a whole * sorted array apart from the buffer.) * * Insertion sorts are O(N^2), but if we cap the size of the * insertion sorts at a constant, then the initial set of * insertion sorts is merely O(constant^2 * N/constant) = * O(N), so it isn't a theoretical obstacle to O(N log N) * complexity overall. */ { size_t sublistlen = INSERTION_THRESHOLD; size_t subliststart, thissublistlen, thissublistlen2; /* Insertion sort pass. */ subliststart = bufsize; while (subliststart < nmemb) { size_t i, j; thissublistlen = sublistlen; if (thissublistlen > nmemb - subliststart) thissublistlen = nmemb - subliststart; for (i = 1; i < thissublistlen; i++) { /* Insertion-sort element i into place. */ j = i; while (j > 0 && COMPARE(subliststart+j-1, subliststart+j) > 0) { SWAP(subliststart+j-1, subliststart+j); j--; } } #ifdef TESTMODE subseq_should_be_sorted(subliststart, thissublistlen); #endif subliststart += thissublistlen; } /* * Merge passes. In each of these we combine sublists of * length sublistlen into sublists of length 2*sublistlen * (with special cases for short lists at the end). */ while (1) { subliststart = bufsize; while (subliststart < nmemb) { thissublistlen = sublistlen; if (thissublistlen > nmemb - subliststart) thissublistlen = nmemb - subliststart; thissublistlen2 = sublistlen; if (thissublistlen2 > nmemb - subliststart - thissublistlen) thissublistlen2 = nmemb - subliststart - thissublistlen; if (thissublistlen2 > 0) merge(base, size, compare CTXARG, bufsize, subliststart, thissublistlen, thissublistlen2); #ifdef TESTMODE subseq_should_be_sorted(subliststart, thissublistlen + thissublistlen2); #endif if (subliststart == bufsize && subliststart + thissublistlen + thissublistlen2 == nmemb) goto merging_done; /* two-level break */ subliststart += thissublistlen + thissublistlen2; } sublistlen *= 2; } merging_done:; } /* * Finally, we must sort the buffer, and then merge it back * into the rest of the sorted array. The stability * requirement here is that we know the buffer contained the * _first_ occurrence of every element in it, so we must * preserve that when distributing it back into the output. */ if (bufsize) { bufsort(base, size, compare CTXARG, 0, bufsize); ldistribute(base, size, compare CTXARG, 0, nmemb, bufsize); } /* * And that's it! One array, stably sorted in place in O(N log * N) time. */ #ifdef TESTMODE subseq_should_be_sorted(0, nmemb); #endif }
TEST (SquareRootTest, ZeroAndNegativeNos) { ASSERT_EQ (0.0, squareroot (0.0)); ASSERT_EQ (-1, squareroot (-22.0)); }
static void merge(void *base, size_t size, cmpfn compare CTXPARAM, size_t bufsize, size_t start, size_t m, size_t n) { size_t s6blksize = squareroot(m+n); size_t s6bufsize = 2*s6blksize + m/s6blksize + n/s6blksize; size_t blkstart, blkend, blksize, blocks, mblocks, nblocks, mextra, nextra; int method; if (m + n <= RECURSION_THRESHOLD) { rmerge(base, size, compare CTXARG, start, m, n); return; } /* * Decide which merge algorithm we're using, and work out the * size of the blocks. */ if (bufsize >= s6bufsize) { method = 6; /* Section 6 standard merge */ blksize = s6blksize; } else { method = 5; /* Section 5 limited-buffer merge */ blksize = (m+n + bufsize - 2) / (bufsize - 1); } /* * We're going to partition our array into blocks of size * blksize, by leaving a partial block at the start and one at * the end so that the m-blocks and n-blocks abut directly. */ mblocks = m / blksize; mextra = m - mblocks * blksize; blkstart = start + mextra; nblocks = n / blksize; nextra = n - nblocks * blksize; blocks = mblocks + nblocks; blkend = blkstart + blocks * blksize; if (mblocks && nblocks) { if (method == 6) { size_t mi, mb, mr, ni, nb, nr, blkindex; size_t mergebufin, mergebufout; /* * Section 6 merge. We need a tracking buffer of size * "blocks", and a merge buffer of size 2*blksize. */ size_t mergebuf = 0; /* start of buffer space */ size_t trackbuf = mergebuf + 2*blksize; assert(trackbuf + blocks <= s6bufsize); /* * Start by sorting the tracking buffer, since we're * going to use it to order the output blocks of the * merge. */ bufsort(base, size, compare CTXARG, trackbuf, blocks); /* * Now simply start reading the two input lists of * blocks, and writing merged output into the merge * buffer. */ mi = blkstart; /* index of next element */ mb = 0; /* index of current block */ mr = blksize; /* elements remaining in that block */ ni = start + m; /* index of next element */ nb = mblocks; /* index of current block */ nr = blksize; /* elements remaining in that block */ mergebufin = mergebufout = 0; while (mi < start + m || ni < blkend) { blkindex = blocks; /* dummy value: no finished block */ /* * Decide which list we're taking an item from. */ if (ni >= blkend || (mi < start + m && COMPARE(mi, ni) <= 0)) { /* Take from the m-list. */ SWAP(mergebufin, mi); mergebufin = (mergebufin + 1) % (2*blksize); mi++; mr--; if (mr == 0) { blkindex = mb++; mr = blksize; } } else { /* Take from the n-list. */ SWAP(mergebufin, ni); mergebufin = (mergebufin + 1) % (2*blksize); ni++; nr--; if (nr == 0) { blkindex = nb++; nr = blksize; } } /* * If we've emptied (i.e. filled with merge buffer * elements) an entire input block on either the * m- or n-side, we now fill it with merge output * data from the merge buffer. */ if (blkindex < blocks) { size_t smallest, i; SWAPN(mergebufout, blkstart + blksize * blkindex, blksize); mergebufout = (mergebufout + blksize) % (2*blksize); /* * Now we must find the smallest as yet unused * element in the tracking buffer, and swap it * into the place matching this block, so that * we know what order to output the blocks in * when we've finished. */ smallest = blkindex; for (i = mb; i < mblocks; i++) if (smallest == blocks || COMPARE(trackbuf + i, trackbuf + smallest) < 0) smallest = i; for (i = nb; i < blocks; i++) if (smallest == blocks || COMPARE(trackbuf + i, trackbuf + smallest) < 0) smallest = i; if (smallest != blkindex) SWAP(trackbuf + blkindex, trackbuf + smallest); } } /* * Our stably merged output list is now sitting in our * block list, except that the blocks are permuted * into some arbitrary wrong order, and the tracking * buffer knows what order that is. So we now * selection-sort the tracking buffer, and swap real * blocks in parallel with the swaps done in that * sort. (Selection sort is used because it uses the * minimum number of swaps, and they're what's * expensive here.) */ { size_t i, j, smallest; for (i = 0; i < blocks; i++) { smallest = i; for (j = i+1; j < blocks; j++) { if (COMPARE(trackbuf + j, trackbuf + smallest) < 0) smallest = j; } if (i != smallest) { SWAP(trackbuf + i, trackbuf + smallest); SWAPN(blkstart + i * blksize, blkstart + smallest * blksize, blksize); } } } /* * And that's our main merge complete. */ } else { size_t firstn, currpos; size_t movedstart = 0, movedend = 0; int movedseq = 0; /* * Sort the buffer. */ bufsort(base, size, compare CTXARG, 0, blocks); /* * Identify the buffer element corresponding to the * first n-block. We will keep this index correct * throughout the following sort, so that we can * always tell which input sequence a given block * belongs to by comparing its corresponding element * in the buffer with this one. */ firstn = mblocks; /* * Selection-sort the blocks by their first element, * breaking ties using the buffer. We also mirror * block swaps in the buffer, and keep firstn up to * date in the process. */ { size_t i, j, smallest; for (i = 0; i < blocks; i++) { smallest = i; for (j = i+1; j < blocks; j++) { int cmp = COMPARE(blkstart + j * blksize, blkstart + smallest * blksize); if (!cmp) cmp = COMPARE(j, smallest); if (cmp < 0) smallest = j; } if (i != smallest) { SWAPN(blkstart + i * blksize, blkstart + smallest * blksize, blksize); SWAP(i, smallest); if (i == firstn || smallest == firstn) firstn = i + smallest - firstn; } } } /* * "currpos" will track the next unmerged element from * here to the end of the array. */ currpos = blkstart; while (currpos < blkend) { int seqA, seqB, cmp; size_t i, apos = currpos, bpos; /* * We're looking at the next unmerged element, * which I'll call A. Find out which original * sequence it's from: usually we do this by * finding the buffer entry corresponding to its * block, although if A is part of a stretch of * the array we moved in a previous iteration then * the buffer may be wrong. */ if (apos >= movedstart && apos < movedend) { seqA = movedseq; bpos = movedend; } else { i = (apos - blkstart) / blksize; seqA = COMPARE(i, firstn) >= 0;/* 0 means m, 1 means n */ bpos = blkstart + (i+1) * blksize; } /* * Search forward to find the next element B from * the _other_ sequence, whichever it is. */ i = (bpos - blkstart) / blksize; seqB = !seqA; while (i < blocks && (COMPARE(i, firstn) >= 0) == seqA) { i++; bpos = blkstart + i * blksize; } /* * If B doesn't exist (we've hit the end of the * list), we've finished! */ if (bpos == blkend) break; /* * Otherwise, see if some merging needs to be * done. If B comes after the element directly * before it (from the other sequence), then we * don't need to move anything just yet. * * (Note that "comes after" must be interpreted * stably, which means we must break ties by * referring to our knowledge of which original * sequences the two elements are from.) */ cmp = COMPARE(bpos-1, bpos); if (cmp == 0) cmp = seqA - seqB; /* break ties correctly */ if (cmp < 0) { /* * This is the easy case: everything from A to * just before B is already correctly merged, * so we can simply advance currpos. */ currpos = bpos; movedstart = movedend = 0; } else { size_t bot, mid, top; size_t cpos; /* * And this is the case where we actually have * to do some work (bah): B must be inserted * somewhere between A and where it currently * is. (Up to and including putting it * _before_ A itself.) So we start by * binary-searching for that insertion point. * Again, we must take care to break * comparison ties in a direction dependent on * seqA and seqB. */ bot = apos-1; top = bpos; while (top - bot > 1) { mid = (top + bot) / 2; cmp = COMPARE(mid, bpos); if (cmp == 0) cmp = seqA - seqB; if (cmp < 0) bot = mid; else top = mid; } cpos = top; /* * Now "cpos" points at some element C of A's * sequence which comes after element B. (The * above search cannot have terminated with * "top" pointing at B itself, because * otherwise we'd be in the easy case above.) * * We can't just move B to that position yet, * though, because there may be further * elements of _B's_ sequence which come * before C. So now we search forward for * those. */ bot = bpos; /* i is still pointing at B's block number; start there. */ while (++i < blocks) { /* * See if we can skip an entire block in * our search. */ if ((COMPARE(i, firstn) >= 0) != seqB) break; /* no, this is A's sequence again */ /* Check the first element of the new block. */ cmp = COMPARE(blkstart + i * blksize, cpos); if (cmp == 0) cmp = seqB - seqA; if (cmp > 0) { break; /* gone too far */ } else { /* yes, we can skip a block */ bot = blkstart + i * blksize; } } /* Now we can binary-search one block only. */ top = bot - (bot-blkstart) % blksize + blksize; while (top - bot > 1) { mid = (top + bot) / 2; cmp = COMPARE(mid, cpos); if (cmp == 0) cmp = seqB - seqA; if (cmp < 0) bot = mid; else top = mid; } /* * Now we're ready. We have a chunk of array * looking like * * apos cpos bpos top * +------+------+----------+ * | P | Q | R | * +------+------+----------+ * * and we know that everything up to cpos is * correctly positioned, and that everything * in stretch R must come before element C (at * the start of stretch Q). So we can * block-exchange Q with R, and update currpos * to point at where the end of R ended up. */ block_exchange(base, size, cpos, bpos - cpos, top - bpos); currpos = cpos + (top - bpos); /* * And record the fact that we've moved * stretch Q, so we know which sequence it * belongs to better than the buffer does. */ movedstart = currpos; movedend = top; movedseq = seqA; } } } } #ifdef TESTMODE /* * Our main block sequence should now be correctly merged. */ subseq_should_be_sorted(blkstart, blkend - blkstart); #endif /* * Now we need to stably distribute the partial blocks from * each end into the main sorted sequence, and we're done. */ ldistribute(base, size, compare CTXARG, start, blkend-start, mextra); rdistribute(base, size, compare CTXARG, start, m+n, nextra); }