use*_*454 8 bash numeric-data excel
我花了几个小时搜索如何在 BASH 中对“浮动数字”进行舍入,但找不到任何正确的!解决方案:( 如果我将这些数字放入 Excel,那么我将在四舍五入到小数点后两位后收到正确的结果:
3.314 -> 3.31
3.315 -> 3.32
8.124 -> 8.12
8.125 -> 8.13
Run Code Online (Sandbox Code Playgroud)
如何在BASH中得到准确的结果?我尝试使用printfandawk但没有得到相同的结果
prompt> printf '%.*f\n' 2 8.125
8.12
prompt> echo '8.125' | awk '{printf("%.2f\n", $1)}'
8.12
Run Code Online (Sandbox Code Playgroud)
Sté*_*las 16
\n\nRun Code Online (Sandbox Code Playgroud)\nprintf \'%.2f\\n\' 8.125\n
将使用标准或C 函数8.125之类的方法将十进制数的文本表示形式转换为内部二进制表示形式,获得一个或二进制浮点数,其内部表示形式将取决于 C 编译器和计算机体系结构。strtod()strtold()doublelong double
然后该数字将通过命令传递printf给printf()标准函数(或其将结果返回为字符串的变体),该函数会将其转换回文本十进制表示形式并进行舍入。这种四舍五入到最接近的四舍五入,一半到偶数(也称为银行家四舍五入)。
您在学校学到的方法存在偏差,因为它往往会平均高估(对于正数)。一半为偶数时, 和 均8.125四舍五入8.115为(偶数8.12)2,一位向下舍入,一位向上舍入。对于大量数字,将其中一半数字向下舍入,另一半向上舍入,就不会引入系统偏差。
现在,这只适用于可以用二进制精确表示的数字。
\n碰巧,8.125 可以用二进制表示。那是 2 3 + 2 -3。8.135 不能。最接近的 IEEE 754 双精度二进制数是 8.1349999999999997868371792719699442386627197265625(转换回十进制时),因此它将转换为 8.13,因为它最接近,而不是偶数 (8.14)。
\n因此,要做你想做的事(甚至进行适当的银行四舍五入),你需要一些不能以二进制工作但以十进制工作的东西。因此,任何在下面使用的东西,printf()包括printf实用程序awk\'s printf(),或者更一般地与处理二进制数的处理器浮点算术功能一起使用,numfmt都是不可能的。
例如,您可以使用python3\'s decimalmodule (如@marcelm 所示)或perl\'s Math::BigFloatmodule and its bfround()function。默认情况下,他们进行银行四舍五入:
$ printf \'%s\\n\' 1.1{0..5}5 | perl -MMath::BigFloat -lne \'print "$_ -> " . Math::BigFloat->new($_)->bfround(-2)\'\n1.105 -> 1.10\n1.115 -> 1.12\n1.125 -> 1.12\n1.135 -> 1.14\n1.145 -> 1.14\n1.155 -> 1.16\nRun Code Online (Sandbox Code Playgroud)\n但你可以切换到与你在学校学到的模式相匹配的common 模式:
$ printf \'%s\\n\' {-,}1.1{0..5}5 +825e-3 0xAAp-6 0x1p100 nan Infinity | \n perl -MMath::BigFloat -lne \'\n print "$_ -> " . Math::BigFloat->new($_)->bfround(-2,common)\'\n-1.105 -> -1.11\n-1.115 -> -1.12\n-1.125 -> -1.13\n-1.135 -> -1.14\n-1.145 -> -1.15\n-1.155 -> -1.16\n1.105 -> 1.11\n1.115 -> 1.12\n1.125 -> 1.13\n1.135 -> 1.14\n1.145 -> 1.15\n1.155 -> 1.16\n+825e-3 -> 0.83\n0xAAp-6 -> 2.66\n0x1p100 -> 1267650600228229401496703205376.00\nnan -> NaN\nInfinity -> inf\nRun Code Online (Sandbox Code Playgroud)\n(显示使用不同符号表示的额外数字)。
\n请注意,类似于python3\ 的方法,但numfmt与某些printf实用程序实现不同,它不区分区域设置。特别是,.即使在否则为 或 的语言环境中,,小数基数字符也将用于输入和输出\xd9\xab。
ste*_*ver 12
如果您的系统使用 GNU coreutils,则numfmt命令应该可用,并允许您在舍入 \xe2\x80\x98up\xe2\x80\x99、\xe2\x80\x98down\xe2\x80\x99、\xe2\ 之间进行选择x80\x98from-zero\xe2\x80\x99(默认值)、\xe2\x80\x98towards-zero\xe2\x80\x99 或 \xe2\x80\x98nearest\xe2\x80\x99。
\n例如(此处在十进制基数字符为 的区域设置中.):
$ numfmt --round=nearest --format %.2f << EOF\n3.314\n3.315\n8.124\n8.125\nEOF\n3.31\n3.32\n8.12\n8.13\nRun Code Online (Sandbox Code Playgroud)\n