AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 759720
Accepted
user3719454
user3719454
Asked: 2023-10-24 19:22:01 +0800 CST2023-10-24 19:22:01 +0800 CST 2023-10-24 19:22:01 +0800 CST

如何像 MS Excel 一样在 bash 中四舍五入到小数点后两位?

  • 772

我花了几个小时搜索如何在 BASH 中对“浮动数字”进行舍入,但找不到任何正确的!解决方案:( 如果我将这些数字放入 Excel,那么我将在四舍五入到小数点后两位后收到正确的结果:

3.314 -> 3.31
3.315 -> 3.32
8.124 -> 8.12
8.125 -> 8.13

如何在BASH中得到准确的结果?我尝试使用printfandawk但没有得到相同的结果

prompt> printf '%.*f\n' 2 8.125
8.12
prompt> echo '8.125' | awk '{printf("%.2f\n", $1)}'
8.12
bash
  • 5 5 个回答
  • 387 Views

5 个回答

  • Voted
  1. Stéphane Chazelas
    2023-10-25T00:29:09+08:002023-10-25T00:29:09+08:00
    printf '%.2f\n' 8.125
    

    将使用标准或C 函数8.125之类的方法将十进制数的文本表示形式转换为内部二进制表示形式,获得一个或二进制浮点数,其表示形式取决于 C 编译器和计算机体系结构。strtod()strtold()doublelong double

    然后该数字将通过命令传递printf给printf()标准函数(或其将结果返回为字符串的变体),该函数会将其转换回文本十进制表示形式并进行舍入。该四舍五入到最接近的四舍五入,一半到偶数(也称为银行家四舍五入)。

    您在学校学到的方法存在偏差,因为它往往会平均高估(对于正数)。一半为偶数时, 和 均四舍五入为(偶数8.125)8.115,8.12一位2向下舍入,一位向上舍入。对于大量数字,将其中一半数字向下舍入,将其中一个向上舍入,就不会引入系统偏差。

    现在,这只适用于可以用二进制精确表示的数字。

    碰巧,8.125 可以用二进制表示。那是 2 3 + 2 -3。8.135 不能。最接近的 IEEE 754 双精度二进制数是 8.1349999999999997868371792719699442386627197265625(转换回十进制时),因此它将转换为 8.13,因为它最接近,而不是偶数 (8.14)。

    因此,要做你想做的事(甚至进行适当的银行四舍五入),你需要一些不能以二进制工作但以十进制工作的东西。因此,任何printf()在下面使用的东西,包括printf实用程序awk's printf(),或者更一般地与处理二进制数的处理器浮点算术功能一起工作,包括numfmt在内,都是不可能的。

    您可以使用 exampleperl的Math::BigFloat模块。默认情况下,它进行银行四舍五入:

    $ printf '%s\n' 1.1{0..5}5 | perl -MMath::BigFloat -lne 'print "$_ -> " . Math::BigFloat->new($_)->bfround(-2)'
    1.105 -> 1.10
    1.115 -> 1.12
    1.125 -> 1.12
    1.135 -> 1.14
    1.145 -> 1.14
    1.155 -> 1.16
    

    但你可以切换到与你在学校学到的模式相匹配的common 模式:

    $ printf '%s\n' {-,}1.1{0..5}5 | perl -MMath::BigFloat -lne 'print "$_ -> " . Math::BigFloat->new($_)->bfround(-2,common)'
    -1.105 -> -1.11
    -1.115 -> -1.12
    -1.125 -> -1.13
    -1.135 -> -1.14
    -1.145 -> -1.15
    -1.155 -> -1.16
    1.105 -> 1.11
    1.115 -> 1.12
    1.125 -> 1.13
    1.135 -> 1.14
    1.145 -> 1.15
    1.155 -> 1.16
    
    • 5
  2. Best Answer
    steeldriver
    2023-10-24T21:53:29+08:002023-10-24T21:53:29+08:00

    如果您的系统使用 GNU coreutils,则numfmt命令应该可用,并允许您在“向上”、“向下”、“从零”(默认)、“向零”或“最近”舍入之间进行选择。

    前任。

    $ numfmt --round=nearest --format %.2f << EOF
    3.314
    3.315
    8.124
    8.125
    EOF
    3.31
    3.32
    8.12
    8.13
    
    • 4
  3. Romeo Ninov
    2023-10-24T21:02:57+08:002023-10-24T21:02:57+08:00

    您可以添加0.005该数字(如学校所教授的那样)以进行计算:

    echo '8.125' | awk '{printf("%.2f\n", $1+0.005)}'
    

    对我来说awk,打印出数字,所以你可以尝试类似的方法:

    echo '8.125' | awk '{printf("%.2f\n", $1+0.001)}'
    
    • 0
  4. Darren H
    2023-10-25T07:56:23+08:002023-10-25T07:56:23+08:00

    没有 printf,没有 perl,只有文本操作

    round2() {
      main=$(echo "$1" | sed -E 's/([0-9]+\.[0-9]{0,2})[0-9]*/\1/g')
      lastDigit="${main: -1}"
      remainder="${1//$main/}"
      
      if [ -z "$remainder" ]; then
        echo $main
        return
      fi
      remFirst="${remainder:0:1}"
    
      if [ "$remFirst" -ge 5 ] && ! [ "$remFirst" -eq 5 -a $((lastDigit % 2)) -eq 0 ]; then
        main_no_decimal=$(echo "$main" | sed 's/\([0-9]*\)\.\([0-9]*\)/\1\2/')
        main_no_decimal=$((main_no_decimal + 1))
        main="${main_no_decimal%??}.${main_no_decimal: -2}"
      fi
    
      echo $main 
    }
    
    round2 5.1
    round2 9
    round2 3.314
    round2 3.315
    round2 8.124
    round2 8.125
    round2 7.205
    round2 1.105
    round2 1.115
    round2 1.125
    round2 1.135
    round2 1.145
    round2 1.155
    round2 100000.185
    

    测试输出

    5.1
    9
    3.31
    3.32
    8.12
    8.12
    7.20
    1.10
    1.12
    1.12
    1.14
    1.14
    1.16
    100000.18
    
    • 0
  5. Chris Davies
    2023-10-25T02:38:05+08:002023-10-25T02:38:05+08:00

    舍入为整数的标准方法是添加 ½ 并截断:

    printf '%s\n' 1.5 2.5 3.5 4.5 |
        awk '{ print int($1 +.5) }'
    

    要实现两位小数乘以 100、截断并再次除法:

    printf '%s\n' 3.314 3.315 8.124 8.125 |
        awk '{ print int(100*$1 +.5)/100 }'
    

    或者

    printf '%s\n' 3.314 3.315 8.124 8.125 |
        awk '{ printf "%0.2f\n", int(100*$1 +.5)/100 }'
    
    • -1

相关问题

  • 通过命令的标准输出以编程方式导出环境变量[重复]

  • 从文本文件传递变量的奇怪问题

  • 虽然行读取保持转义空间?

  • `tee` 和 `bash` 进程替换顺序

  • 运行一个非常慢的脚本直到它成功

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve