如何修改浮点数以显示至少 n 位数字

How to modify a float to display at least n digits

在 bash 中,如何修改 float 以使点之前的部分至少有两位数?

我想让 A 列 中的数字显示为 B 列:

A (Current)   B (Desired)
-----         ------
8.456         08.456
4.19          04.19
3.5           03.5

我做了很多搜索,但我发现的大部分内容都在谈论如何显示带有 N 小数位的数字(例如 17.7647 to 17.76),这没有任何帮助.

how can I modify a float so that the part coming before the dot is having at least two digits.

没有实用程序 - 编写您自己的代码来执行此操作。你会:

  • 计算逗号前的位数
  • 如果位数小于2
    • 如果位数是1
      • 前加一个零
    • 如果为零
      • 添加两个前导零

我还可以看到 sed 有两个表达式,每个表达式都与正则表达式匹配逗号前的位数。

这是 bash 中的实用函数,使用 printf 实现此目的:

fpad() {
   local n="${1?needs an argument}"
   [[ $n == [0-9].* ]] && echo "0$n" || echo "$n"
}

用作:

fpad "8.456"
08.456

fpad "4.19"
04.19

fpad "3.5"
03.5

fpad "13.25"
13.25

fpad "1325"
1325

将 Glen 的建议与 read 结合使用:

fpad() {
   local n="${1?needs an argument}"
   local num frac
   IFS=. read num frac <<< "$n"
   printf '%02d.%d\n' "$num" "$frac"
}

您可以扩展一点,通过允许设置实部和小数部分的宽度并完全验证输入并处理任何错误,进一步扩展 @anubhava 的好答案在你的功能中。虽然方法是相同的,但使用 printf 格式字符串是关键。

例如,您的函数可以将浮点数作为第一个参数,将实部的宽度作为第二个参数,并可选择将小数部分的宽度作为第三个参数,例如

#!/bin/bash

formatfloat () {
    [ -z "" -o -z "" ] && { ## validate at least 2 arguments given
        printf "error: formatfloat() insufficient arguments.\n" >&2
        printf "usage: formatfloat() float width_real [width_fract]\n" >&2
        return 1;
    }
    [[  =~ ^-*[[:digit:]]*[.][[:digit:]]* ]] || { ## validate float
        printf "error: formatfloat() not a valid floating point number.\n" >&2
        return 1
    }
    [ "" -eq "" > /dev/null ] || {  ## validate width is an integer
        printf "error: formatfloat() width_real not an integer.\n" >&2
        return 1
    }
    local realpart="${1%.*}"    ## parameter expansion separates real/fraction parts
    local fractpart="${1#*.}"
    local width_real=""
    
    if [ -n "" ]; then                    ## if fractional part width given
        [ "" -eq "" > /dev/null ] || {  ## validate it is an integer
            printf "error: formatfloat() width_fract not an integer.\n" >&2
            return 1
        }
        local width_fract=""  ## output setting both widths
        local fppad="$((width_fract - ${#fractpart}))"  ## needed fract part rt-pad
        [ "$fppad" -le 0 ] && { ## no padding needed
            printf "%0*d.%d\n" $width_real $realpart $fractpart
            return 0
        }
        for ((i = 0; i < fppad; i++)); do   ## add padding to fract part
            fractpart="${fractpart}0"
        done
        printf "%0*d.%*d\n" $width_real $realpart $width_fract $fractpart
    else                        ## output setting real-part width
        printf "%0*d.%d\n" $width_real $realpart $fractpart
    fi
    
    return 0
}

您的数据的一个简短示例可以是:

printf "A (Current)   B (Desired)\n-----         ------\n"

for n in 8.456 4.19 3.5; do
    printf "%-14s%s\n" "$n" "$(formatfloat "$n" 2)"
done

输出

$ bash formatfloat.sh
A (Current)   B (Desired)
-----         ------
8.456         08.456
4.19          04.19
3.5           03.5

设置两者的宽度


for n in 8.456 4.19 3.5; do
    printf "%-14s%s\n" "$n" "$(formatfloat "$n" 2 3)"
done

输出

$ bash formatfloat.sh
A (Current)   B (Desired)
-----         ------
8.456         08.456
4.19          04.190
3.5           03.500