作者oopFoo (3d)
看板Soft_Job
标题Re: [讨论] 请大家聊聊 JavaScript的缺陷
时间Fri Jan 16 21:55:26 2026
怎麽会是banker's rounding?
完全是float/double无法精准代表fraction的问题。
https://www.h-schmidt.net/FloatConverter/IEEE754.html
https://www.binaryconvert.com/convert_double.html
你可以看到在float,0.005实际上是0.004999999888241291046142578125
但在double, 0.005是0.00500000000000000010408340855861
浮点只能找个最接近0.005,但并不是真正的0.005。
所以rounding会往上或往下,是取决於最接近的浮点是>5或 <5。
你的程式对了,但你的ai怎麽结论怎麽会是banker's rounding?
※ 引述《descent (「雄辩是银,沉默是金」)》之铭言:
: 对这问题很好奇, c++ 也有类似的情形。
: 1 #include <iostream>
: 2 #include <string>
: 3 #include <cmath>
: 4 using namespace std;
: 5
: 6 int main(int argc, char *argv[])
: 7 {
: 8 std::cout.precision(2);
: 9 cout << fixed << 0.005 << endl;
: 10 cout << 0.015 << endl;
: 11 cout << 0.025 << endl;
: 12 cout << 0.035 << endl;
: 13 cout << 0.045 << endl;
: 14 cout << 0.055 << endl;
: 15 cout << 0.065 << endl;
: 16 cout << 0.075 << endl;
: 17 cout << 0.085 << endl;
: 18 cout << 0.095 << endl;
: 19 return 0;
: 20 }
: n.cpp 执行结果
: 0.01
: 0.01
: 0.03
: 0.04
: 0.04
: 0.06
: 0.07
: 0.07
: 0.09
: 0.10
: 藉由 ai, 终於知道是怎麽回事, 当决定要印出小数点 2 位数时候用的演算法是
: 「偶数舍入法」(Banker's Rounding) 这是很多绘图、统计或会计系统的规则:
: 若刚好在 .5 的位置, 则舍入到最接近的「偶数」。
: 0.005 → 靠近 0.00 还是 0.01? 这里 0 是偶数, 所以会趋向 0.00, 但在电脑里
: 0.005 是 0.00500000000000000010 所以它判断靠近 0.01。
: 0.015 → 靠近 0.01 还是 0.02? 这里 2 是偶数, 本应往 0.02 走, 但在电脑里 0.015
: 是 0.0149..., 所以它决定留在 0.01。
: 另外也请 ai 给出一个简易版本的演算法, 实作 Banker's Rounding。
: fn.cpp
: 1 #include <iostream>
: 2 #include <iomanip> // 必须包含此库以使用 setprecision
: 3
: 4 #include <cmath>
: 5 #include <string>
: 6 #include <cstdio>
: 7
: 8 using namespace std;
: 9
: 10 /**
: 11 * 模拟 setprecision(2) + fixed 的行为
: 12 * @param value 要输出的数值
: 13 * @param precision 小数点後位数
: 14 */
: 15 void my_print_fixed(double value, int precision) {
: 16 cout << fixed << setprecision(20) << value << endl;
: 17
: 18 // 1. 取得放大倍数 (例如 precision 2 则为 100)
: 19 long double multiplier = std::pow(10, precision);
: 20
: 21 // 2. 模拟底层舍入规则
: 22 // 注意:std::round 在这里会反映出 0.015 储存成 0.01499... 的事实
: 23 double rounded_value = std::round(value * multiplier) / multiplier;
: 24
: 25 // 3. 格式化输出字串
: 26 // 我们用 printf 的格式化字串来模拟输出流的最後一步
: 27 char format[10];
: 28 sprintf(format, "%%.%df", precision);
: 29 printf("Input: %.20f | Result: ", value);
: 30 printf(format, rounded_value);
: 31 printf("\n");
: 32 }
: 33
: 34 int main() {
: 35 double n1 = 0.005;
: 36 double n2 = 0.015;
: 37
: 38 std::cout << "--- 模拟底层数值转换 ---" << std::endl;
: 39
: 40 // 看看 0.005 实际上在想什麽
: 41 my_print_fixed(n1, 2);
: 42
: 43 // 看看 0.015 实际上在想什麽
: 44 my_print_fixed(n2, 2);
: 45
: 46 n2 = 0.025;
: 47 my_print_fixed(n2, 2);
: 48 n2 = 0.035;
: 49 my_print_fixed(n2, 2);
: 50 n2 = 0.045;
: 51 my_print_fixed(n2, 2);
: 52 n2 = 0.055;
: 53 my_print_fixed(n2, 2);
: 54 n2 = 0.065;
: 55 my_print_fixed(n2, 2);
: 56 n2 = 0.075;
: 57 my_print_fixed(n2, 2);
: 58 n2 = 0.085;
: 59 my_print_fixed(n2, 2);
: 60 n2 = 0.095;
: 61 my_print_fixed(n2, 2);
: 62 return 0;
: 63 }
: list 5 fn.cpp 执行结果
: 1 --- 模拟底层数值转换 ---
: 2 0.00500000000000000010
: 3 Input: 0.00500000000000000010 | Result: 0.01
: 4 0.01499999999999999944
: 5 Input: 0.01499999999999999944 | Result: 0.01
: 6 0.02500000000000000139
: 7 Input: 0.02500000000000000139 | Result: 0.03
: 8 0.03500000000000000333
: 9 Input: 0.03500000000000000333 | Result: 0.04
: 10 0.04499999999999999833
: 11 Input: 0.04499999999999999833 | Result: 0.04
: 12 0.05500000000000000028
: 13 Input: 0.05500000000000000028 | Result: 0.06
: 14 0.06500000000000000222
: 15 Input: 0.06500000000000000222 | Result: 0.07
: 16 0.07499999999999999722
: 17 Input: 0.07499999999999999722 | Result: 0.07
: 18 0.08500000000000000611
: 19 Input: 0.08500000000000000611 | Result: 0.09
: 20 0.09500000000000000111
: 21 Input: 0.09500000000000000111 | Result: 0.10
: 另外注意 fn.cpp L19, 需要用 long double, 如果用 double 结果 0.015 印出来会
: 是 0.02, 因为演算法 L23 value * multiplier 0.014999999999999999 X 100
: 变成是 1.50000000000000000000, 而不是 1.4999,
: 需要使用精度更高的 long double 才会是 1.4999。
: ※ 引述《accessdenied (存取违规)》之铭言:
: : https://i.imgur.com/inyE92c.jpg
: : 有谁可以告诉我,JavaScript 的 toFixed()为什麽遇到1,4,7这几个数字後面的5不会
: : 进位呢?
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 58.114.66.74 (台湾)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/Soft_Job/M.1768571731.A.634.html
1F:推 sceleton: 推! 01/16 23:39
2F:→ wuyiulin: 同意,我刚刚在看他测资跑起来就想说跟 banker's round 01/17 02:48
3F:→ wuyiulin: ing 有啥关系,不就二进位误差(#。 01/17 02:48
4F:→ jonathan793: 就...有人大学没认真念 ai随便唬就信了 01/17 12:12
5F:→ jonathan793: 糗的是还沾沾自喜发文 01/17 12:12
6F:推 descent: 感谢补充 01/17 13:28