C_and_CPP 板


LINE

谢谢回应 这次乌龙了 以下为 藉由这讨论的机缘 衍生的双态议题 将原qsort 改成采用回覆bool 型态的compare routine. 初步实验 5, 6, 8, 10, 20, 30 个 double inputs 都还正确 在sort doubles 异值多时 会比3态的好些 同值多时 会慢些 另外 shortsort() 也要改一下 (没贴code) bool compare_record( const void *arg1, const void *arg2 ) { return ( (*(s_reorder *)arg2).value> (*(s_reorder *)arg1).value); } //把所有用到compare的地方 改成采用 bool 逻辑 void qsort_ ( void *base, size_t num, size_t width, bool ( *comp)(const void *, const void *) ) { char *lo, *hi; /* ends of sub-array currently sorting */ char *mid; /* points to middle of subarray */ char *loguy, *higuy; /* traveling pointers for partition step */ size_t size; /* size of the sub-array */ char *lostk[STKSIZ], *histk[STKSIZ]; int stkptr; /* stack for saving sub-array to be processed */ if (num < 2) return; /* nothing to do */ stkptr = 0; /* initialize stack */ lo = (char *)base; hi = (char *)base + width * (num-1); /* initialize limits */ /* this entry point is for pseudo-recursion calling: setting lo and hi and jumping to here is like recursion, but stkptr is preserved, locals aren't, so we preserve stuff on the stack */ recurse: size = (hi - lo) / width + 1; /* number of el's to sort */ /* below a certain size, it is faster to use a O(n^2) sorting method */ if (size <= CUTOFF) { __SHORTSORT(lo, hi, width, comp, context); } else { /* First we pick a partitioning element. The efficiency of the algorithm demands that we find one that is approximately the median of the values, but also that we select one fast. We choose the median of the first, middle, and last elements, to avoid bad performance in the face of already sorted data, or data that is made up of multiple sorted runs appended together. Testing shows that a median-of-three algorithm provides better performance than simply picking the middle element for the latter case. */ mid = lo + (size / 2) * width; /* find middle element */ /* Sort the first, middle, last elements into order */ if (__COMPARE(context, lo, mid) ) { swap(lo, mid, width); } if (__COMPARE(context, lo, hi) ) { swap(lo, hi, width); } if (__COMPARE(context, mid, hi) ) { swap(mid, hi, width); } /* We now wish to partition the array into three pieces, one consisting of elements <= partition element, one of elements equal to the partition element, and one of elements > than it. This is done below; comments indicate conditions established at every step. */ loguy = lo; higuy = hi; /* Note that higuy decreases and loguy increases on every iteration, so loop must terminate. */ for (;;) { /* lo <= loguy < hi, lo < higuy <= hi, A[i] <= A[mid] for lo <= i <= loguy, A[i] > A[mid] for higuy <= i < hi, A[hi] >= A[mid] */ /* The doubled loop is to avoid calling comp(mid,mid), since some existing comparison funcs don't work when passed the same value for both pointers. */ if (mid > loguy) { do { loguy += width; } while (loguy < mid && !__COMPARE(context, loguy, mid) ); } if (mid <= loguy) { do { loguy += width; } while (loguy <= hi && !__COMPARE(context, loguy, mid) ); } /* lo < loguy <= hi+1, A[i] <= A[mid] for lo <= i < loguy, either loguy > hi or A[loguy] > A[mid] */ do { higuy -= width; } while (higuy > mid && __COMPARE(context, higuy, mid) ); /* lo <= higuy < hi, A[i] > A[mid] for higuy < i < hi, either higuy == lo or A[higuy] <= A[mid] */ if (higuy < loguy) break; /* if loguy > hi or higuy == lo, then we would have exited, so A[loguy] > A[mid], A[higuy] <= A[mid], loguy <= hi, higuy > lo */ swap(loguy, higuy, width); /* If the partition element was moved, follow it. Only need to check for mid == higuy, since before the swap, A[loguy] > A[mid] implies loguy != mid. */ if (mid == higuy) mid = loguy; /* A[loguy] <= A[mid], A[higuy] > A[mid]; so condition at top of loop is re-established */ } /* A[i] <= A[mid] for lo <= i < loguy, A[i] > A[mid] for higuy < i < hi, A[hi] >= A[mid] higuy < loguy implying: higuy == loguy-1 or higuy == hi - 1, loguy == hi + 1, A[hi] == A[mid] */ /* Find adjacent elements equal to the partition element. The doubled loop is to avoid calling comp(mid,mid), since some existing comparison funcs don't work when passed the same value for both pointers. */ /* 这里去掉 higuy += width; if (mid < higuy) { do { higuy -= width; } while (higuy > mid && __COMPARE(context, higuy, mid) == 0); } if (mid >= higuy) { do { higuy -= width; } while (higuy > lo && __COMPARE(context, higuy, mid) == 0); } */ /* OK, now we have the following: higuy < loguy lo <= higuy <= hi A[i] <= A[mid] for lo <= i <= higuy A[i] == A[mid] for higuy < i < loguy A[i] > A[mid] for loguy <= i < hi A[hi] >= A[mid] */ /* We've finished the partition, now we want to sort the subarrays [lo, higuy] and [loguy, hi]. We do the smaller one first to minimize stack usage. We only sort arrays of length 2 or more.*/ if ( higuy - lo >= hi - loguy ) { if (lo < higuy) { lostk[stkptr] = lo; histk[stkptr] = higuy; ++stkptr; } /* save big recursion for later */ if (loguy < hi) { lo = loguy; goto recurse; /* do small recursion */ } } else { if (loguy < hi) { lostk[stkptr] = loguy; histk[stkptr] = hi; ++stkptr; /* save big recursion for later */ } if (lo < higuy) { hi = higuy; goto recurse; /* do small recursion */ } } } /* We have sorted the array, except for any pending sorts on the stack. Check if there are any, and do them. */ --stkptr; if (stkptr >= 0) { lo = lostk[stkptr]; hi = histk[stkptr]; goto recurse; /* pop subarray from stack */ } else return; /* all subarrays done */ } 其一实验结果 133.189934 1 133.189934 2 133.189934 0 -2.757893 27 -2.757893 29 -2.757893 28 -3.101130 26 -3.101130 25 -3.101130 24 -3.528712 23 -3.528712 22 -3.528712 21 -4.839155 20 -4.839155 19 -4.839155 18 -4.985885 16 -4.985885 17 -4.985885 15 -14.652165 14 -14.652165 13 -14.652165 12 -15.586037 11 -15.586037 10 -15.586037 9 -21.296681 8 -21.296681 7 -21.296681 6 -41.253111 3 -41.253111 5 -41.253111 4 对了 我也试过用 (int) (double a - double b) 回传 因为顺序不需用到太精确 心想差异值小於1 的顺序错 还可以忍受 可是发现满多错的地方差异值都大於1 以致乌龙误认 谢谢指教 ※ 引述《zhim (zhim)》之铭言: : 标题: Re: [闲聊] VC2005 的 qsort 好像有bug... : 时间: Thu Dec 3 04:57:53 2009 : : 谢谢回应 : : 本人回应太慢 对不起 : : 我也不是很有把握 : : 我用内建的IDE 测了不同的 data type, int, float, double : : 只有double 20个时 发生问题 ( 测试个数 5, 6, 8, 10, 20) : : 我把code贴上来 请各位指教一下 : : : : typedef struct _record_ : { : double value; : int position; : } s_reorder; : : int compare_record( const void *arg1, const void *arg2 ) : { : return (int) ( (*(s_reorder *)arg2).value> (*(s_reorder *)arg1).value); : } : : : int main(void) : { : // reorder 是一维阵列 , size= m> 20, 没有相同的element : : qsort( (void *)( reorder), (size_t) m, sizeof( s_reorder), compare_record ); : : } : : 我用相同的资料结构 自己写一个 _qsort_ 没再多呼叫compare 是正确的结果 : 我记得当初debug时 有把structure 拿掉 还是相同的情形 : 一两个月前了 又因为自己写了_qsort_也还好 : 就没再多做实验 也有些情况没记那麽清楚 好像 30, 40, 50 个double 都有错 : 最近程式告一段落 才想来问看看... : : 以下是错的结果 : 0 121.714397 : 1 -0.785398 : 2 -2.520560 : 3 -0.791447 : 4 -0.855704 : 5 -1.695513 : 6 -1.455394 : 7 -1.857532 : 8 -2.066145 : 9 -3.284361 : 10 -2.275599 : 11 -3.423782 : 12 -3.641737 : 13 -5.068104 : 14 -6.149263 : 15 -7.107637 : 16 -10.794325 : 17 -15.191077 : 18 -17.749103 : 19 -35.001716 : : : 谢谢罗 : : : ※ 引述《zhim (zhim)》之铭言: : : 标题: [闲聊] VC2005 的 qsort 好像有bug... : : 时间: Wed Dec 2 06:08:56 2009 : : : : 用VC2005内建的qsort : : : : 帮20个 double排序 好像会得出错的顺序 : : : : 不知是否有人有相同的经验? : : : : 还是MS 已经有patch了... : : : : : : 希望 patch != VC2008 .... : : : : : : -- : :



※ 发信站: 批踢踢实业坊(ptt.cc)
: : ◆ From: 140.115.51.64 : : → sunneo:你有在别的IDE测试吗 12/02 08:38 : : 推 LPH66:你是怎麽写的...? 12/02 08:39 : : 推 ledia:通常是自己写错 12/02 09:18 : : → ledia:(这里的通常, 大约是 99.99%) 12/02 09:18 : : → VictorTom:写程式结果有错都不会先怀疑自己写错就觉得是环境给的 12/02 09:30 : : → VictorTom:lib有错吗Orz 这麽有自信的话直接贴code来看就知道了XD 12/02 09:30 : : → tomnelson:(99.9% + 0.1%)写错... 12/02 10:51 : : → tomnelson:我敢猜问题出在那个传入qsort的cmpfunc(比较函式)... 12/02 10:55 : : → tomnelson:题外话,写程式出问题就怪罪到IDE或compiler,不是好事,虽 12/02 10:57 : : → tomnelson:然这种事也真的有,但是在已经成熟而且在市面上的产品上 12/02 10:58 : : → tomnelson:来说,真的少见,顶多是在compiler最佳化那边出问题,这种 12/02 11:00 : : → tomnelson:内建functions出问题的,还没遇过. 12/02 11:00 : : → tomnelson:请参考别人"犯错心得"如下两网址: 12/02 11:12 : : → tomnelson:http://ppt.cc/kPN0 12/02 11:13 : : → tomnelson:http://ppt.cc/Ctst 12/02 11:13 : : 推 ledia:我隔空抓药一下, 他大概回传 *(double*)x-*(double*)y; 12/02 13:22 : : → ledia:当 x, y 差距太小, 回传又 cast 成 int 就会变为 0 ... 12/02 13:22 : : → bugmens:原po都不吭声,大家debug倒是解的很高兴 12/02 18:07 : : 推 walker2009:楼上是bug, 抓到了 XD 12/02 18:44 : : → sunneo:大家都讲得太明了 -.- 我反倒想看看他测了几个IDE来下结论 12/02 22:27 : : -- :



※ 发信站: 批踢踢实业坊(ptt.cc)
: ◆ From: 140.115.51.64 : 推 ducksteven:http://codepad.org/uYuEtII3 12/03 05:05 : 推 ducksteven:我在自己的电脑编译也会跑错,改成这样就不会错了 12/03 05:09 : → ducksteven:http://codepad.org/TLz5KfGt 12/03 05:09 : → ducksteven:上面有人提示了,因为它有 3 种 return value 12/03 05:10 : → zhim:谢谢您 VC要3种value不是变慢了, 我以前用BC3都没注意到这个 12/03 05:33 : 推 VictorTom:果然被人抓药抓对了, 应该回传三态你只回传两态.... 12/03 09:13 : → VictorTom:http://0rz.tw/tR11X 12/03 09:14 : → VictorTom:只能说你以前没遇到错误大概只是运气好.... 12/03 09:15 : → VictorTom:效率会不会变差要看lib内部怎麽实作, 如果它本来就需要 12/03 09:18 : → VictorTom:三态你只给两态, 结果错了就更不用讨论效率了XD 12/03 09:19 : → tomnelson:哈哈哈~~~ 12/03 11:38 : 推 ducksteven:它的定义本来就有三种回传啊 顺便告诉你我编译器是gcc 12/03 13:36 : 推 cplusplus:下次先看document会比较好... C的标准qsort本来就要三态 12/03 15:33 : → tomnelson:"man 3 qsort" for Linux/Unix/FreeBSD and etc. ! 12/03 17:48 : → sunneo:数字三态最简单就是直接a-b了 12/03 21:52 : → zhim:这样就会发生 a-b -> 0 的 round off error 12/04 14:11 : → zhim:双态就够了 把qsort.c 检查 ==0 的去掉 12/04 14:14 : → zhim:其他改成 bool 逻辑 12/04 14:18 : 推 ledia:bool ? 回传 0, 1 就是会错呀... 12/04 14:59 : → ledia:你可以只传 -1, 1 啦, 我想没有 0 大概不会有太大问题 12/04 14:59 : → ledia:只回传 0, 1 就注定会错了 12/04 14:59 --



※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 140.115.51.64
1F:推 ledia:所以你做了一个只有你自己能用的 qsort ... @@"" 12/05 01:03
2F:→ ledia:而且也不会快多少 12/05 01:04
3F:→ tomnelson:重新造轮子,不鼓励这麽做,而且如楼上说的,不会快多少,甚 12/05 01:11
4F:→ tomnelson:至会比原先qsort还慢,因为很多内建函式都有做过最佳化! 12/05 01:12
5F:→ zhim:只要有心 人人都可以把内建最佳化的code再拿来改... 12/05 03:03
6F:推 AstralBrain:还不如去用std::sort 12/05 03:05
7F:→ zhim:效率评估 假设比较 ==发生机率为 1/3, 2*1/3+1/3 -> 1*2*1/3 12/05 03:15
8F:→ zhim:(2/3n lg 2/3n)+ 1/3n -> 2/3 n lg n 平均起来有些好处 12/05 03:26
9F:→ sunneo:std::sort已经作过快取以及问题处理上的最佳化了 12/05 03:38
10F:→ sunneo:只要有心 你就可以只花10行以内作到最好 12/05 03:39
11F:→ bugmens:引言太多,内文的程式码也没用置底文处理,END 12/05 05:45
12F:推 ledia:你只是把那 1/3 拿去分散给其它两个 case 罢了.... XD 12/05 22:30
13F:→ ledia:不检查等於关系, 适必表示他们一定会有大小关系 12/05 22:31
14F:→ ledia:还不是要拿来 compare ? 12/05 22:31
15F:→ VictorTom:有心去常识研究改良现有的方法这种企图心很好, 但是这类 12/05 22:33
16F:→ VictorTom:实作印象中都是经过验证的, 要如何才能证明自己改过的版 12/05 22:34
17F:→ VictorTom:本的效能, 正确性, 与稳定性等, 都>=原版本的表现呢@_@" 12/05 22:34
18F:推 ledia:C stdlib 的 qsort 满逊的, 要就去跟 std:sort 比吧 XD 12/05 22:58







like.gif 您可能会有兴趣的文章
icon.png[问题/行为] 猫晚上进房间会不会有憋尿问题
icon.pngRe: [闲聊] 选了错误的女孩成为魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一张
icon.png[心得] EMS高领长版毛衣.墨小楼MC1002
icon.png[分享] 丹龙隔热纸GE55+33+22
icon.png[问题] 清洗洗衣机
icon.png[寻物] 窗台下的空间
icon.png[闲聊] 双极の女神1 木魔爵
icon.png[售车] 新竹 1997 march 1297cc 白色 四门
icon.png[讨论] 能从照片感受到摄影者心情吗
icon.png[狂贺] 贺贺贺贺 贺!岛村卯月!总选举NO.1
icon.png[难过] 羡慕白皮肤的女生
icon.png阅读文章
icon.png[黑特]
icon.png[问题] SBK S1安装於安全帽位置
icon.png[分享] 旧woo100绝版开箱!!
icon.pngRe: [无言] 关於小包卫生纸
icon.png[开箱] E5-2683V3 RX480Strix 快睿C1 简单测试
icon.png[心得] 苍の海贼龙 地狱 执行者16PT
icon.png[售车] 1999年Virage iO 1.8EXi
icon.png[心得] 挑战33 LV10 狮子座pt solo
icon.png[闲聊] 手把手教你不被桶之新手主购教学
icon.png[分享] Civic Type R 量产版官方照无预警流出
icon.png[售车] Golf 4 2.0 银色 自排
icon.png[出售] Graco提篮汽座(有底座)2000元诚可议
icon.png[问题] 请问补牙材质掉了还能再补吗?(台中半年内
icon.png[问题] 44th 单曲 生写竟然都给重复的啊啊!
icon.png[心得] 华南红卡/icash 核卡
icon.png[问题] 拔牙矫正这样正常吗
icon.png[赠送] 老莫高业 初业 102年版
icon.png[情报] 三大行动支付 本季掀战火
icon.png[宝宝] 博客来Amos水蜡笔5/1特价五折
icon.pngRe: [心得] 新鲜人一些面试分享
icon.png[心得] 苍の海贼龙 地狱 麒麟25PT
icon.pngRe: [闲聊] (君の名は。雷慎入) 君名二创漫画翻译
icon.pngRe: [闲聊] OGN中场影片:失踪人口局 (英文字幕)
icon.png[问题] 台湾大哥大4G讯号差
icon.png[出售] [全国]全新千寻侘草LED灯, 水草

请输入看板名称,例如:iOS站内搜寻

TOP