【问题标题】:awk float point representationawk 浮点数表示
【发布时间】:2023-04-11 01:51:01
【问题描述】:

嘿,我是 shell 脚本的新手,我正在尝试编写一些涉及浮点计算的东西。我打算使用 bc 或 awk。

但是,由于我找不到告诉 bc 正确执行 x^(1/3) 的方法,我最终选择了 awk。除了一个问题,我什么都做完了:对于用 awk 进行除法,每当我的除数小于 1 时,比如 0.0064,awk 似乎将其读取为 0。因此我得到了 inf 作为结果。我不确定我哪里做错了。

这是我的代码,我需要将计算的值存储到变量中,不一定要打印出来。

我也很好奇 bc、awk 或 simple expres'' 形式如何处理值?它们是作为数值还是字符串读取/存储?

另外,只是为了使用 awk 作为计算,我可以做 x=$(echo "expression" | awk) 或类似的东西,而不使用 awk '{ }' 中的 print 表达式吗?

#!/bin/bash


# molar concentration = 0.1 mM per nm^3
MOLAR=0.0001
NA=6.02*10^23
CONV=1*10^24

number_concentration=$(echo "scale=10;$MOLAR * $NA / ($CONV)" | bc)
echo $number_concentration

# determine box size
volume=$(awk 'BEGIN {print 1+$number_concentration}' /dev/null)
echo $volume

# length
a=$(echo awk 'BEGIN {$volume^(1/3)}' /dev/null)

【问题讨论】:

  • shell sn-p 无法正常工作,因为您的变量根本没有在 awk 脚本中使用。您将脚本放在单引号中,因此 shell 不会扩展您的变量值。我会使用 awk 的 -v 参数将值传递给 awk。
  • 我使用了双引号,它有效!谢谢!
  • 0.0064 小于 0?
  • wrt I used the double quotes and it works! - 这是一个糟糕的主意,因为它会导致在你的 awk 脚本中引用和逃避地狱。不要这样做,因为它完全没有必要。
  • 嘿,Ed,您能详细说明一下您的 cmets 吗?对不起,我对脚本很陌生,所以我不太明白你的意思。

标签: bash shell awk


【解决方案1】:

我会这样写,只需调用一次 awk:

MOLAR="0.0001"
NA="6.02*10^23"
CONV="1*10^24"

read concentration volume length < <(
    awk "BEGIN {
        molar=$MOLAR; na=$NA; conv=$CONV
        conc = molar * na / conv
        vol = 1 + conc
        len = vol ^ (1/3)
        printf \"%.8f %.8f %.8f\\n\", conc, vol, len
    }"
)

printf "%s\n" $concentration $volume $length
0.00006020
1.00006020
1.00002007

请注意,您可能会遇到浮点数精度损失的问题:

% awk "BEGIN {print $MOLAR, $NA, $CONV}"
0.0001 601999999999999928696832 999999999999999983222784

如果 bash 变量可以用“科学记数法”表示,那么我们就可以了:

MOLAR="0.0001"
NA="6.02e23"
CONV="1e24"

awk  -v molar="$MOLAR" -v na="$NA" -v conv="$CONV" 'BEGIN {
    conc = molar * na / conv
    vol = 1 + conc
    len = vol ^ (1/3)
    printf "%.8f %.8f %.8f\n", conc, vol, len
}'

【讨论】:

  • 感谢您的帮助!你能解释一下 awk (命令)会返回什么吗?一组值还是因为read命令可以这样使用awk?
  • 读取命令获取 awk 打印出的三个值(通过 printf 行)并将它们设置到 shell 变量中。
  • NA 将被截断为 6.02CONV1。这真的是我们想要的吗?
  • 因为对于 NA,您正在使用“6.02*10^23”的数字字符串,然后对其执行算术运算,告诉 awk 将其转换为数字,并且 awk 使用的过程这样做就是切断数字字符串中最后一个数字之后的所有内容,即从 '*' 开始的所有内容,因此它以前导“6.02”结束
  • 是的,你是对的。我会修复的。谢谢 Ed,感谢您的评论。
【解决方案2】:

您可以使用echoawk 来执行此操作。

#!/bin/bash


# molar concentration = 0.1 mM per nm^3
MOLAR=0.0001
NA=6.02*10^23
CONV=1*10^24

number_concentration=$(echo "$MOLAR $NA $CONV" | awk '{print $1*$2/$3}')
echo $number_concentration

# determine box size
volume=$(echo "$number_concentration" | awk '{print 1+$1}')
echo $volume

# length
a=$(echo $volume | awk '{print $1^(1/3)}')
echo $a

【讨论】:

  • 感谢您的更改!你能解释一下为什么我们需要打印评论吗? awk 会执行算术运算吗?
  • awk 会将值打印到分配给变量的标准输出,volume, a 等...
  • 你需要 print 来获取 awk 来打印算术的结果。否则它不会去任何地方,你的作业也看不到它。
【解决方案3】:

难道你不能全部在 awk 中完成吗?

awk 'BEGIN {
    molar = 0.0001
    na    = 6.02   * 10 ^ 23
    conv  = 1      * 10 ^ 24

    number_concentration = molar * na / conv
    volume = 1 + number_concentration
    a = volume ^ (1/3)

    print number_concentration, volume, a
}'  
6.02e-05 1.00006 1.00002

如果您需要不同的输出格式,请使用 printf 而不是 print

如果您出于某种原因需要在 awk 脚本之前在 shell 中定义变量:

MOLAR="0.0001"
NA="6.02*10^23"
CONV="1*10^24"

awk 'BEGIN {
    molar = '"$MOLAR"'
    na    = '"$NA"'
    conv  = '"$CONV"'

    number_concentration = molar * na / conv
    volume = 1 + number_concentration
    a = volume ^ (1/3)

    print number_concentration, volume, a
}'
6.02e-05 1.00006 1.00002

或者甚至不使用 awk 变量作为初始值:

MOLAR="0.0001"
NA="6.02*10^23"
CONV="1*10^24"

awk 'BEGIN {
    number_concentration = ('"$MOLAR"') * ('"$NA"') / ('"$CONV"')
    volume = 1 + number_concentration
    a = volume ^ (1/3)

    print number_concentration, volume, a
}'   
6.02e-05 1.00006 1.00002

请注意,上述方法不是在 awk 脚本中访问 shell 变量值的常规方法,通常你会使用 awk -v awkvar="$shellvar" ... 传递它们的值,但在这种情况下,我们需要 shell 的实际文本扩展变量在被 awk 解释之前发生在 awk 脚本中,而通常由于潜在的破坏,这种行为是不受欢迎的,因为 shell 变量可能会扩展为导致 awk 语法错误或其他不良行为的东西。

因此,仅对数字执行此操作(数字表达式可能是此操作的唯一用途):

awk 'BEGIN{awkvar='"$shellvar"'} {script}'

或者 this 用于字符串(不确定这是否真的有必要):

awk 'BEGIN{awkvar="'"$shellvar"'"} {script}'

优先于此:

awk -v awkvar="$shellvar" '{script}'

当您完全控制 shellvar 的内容时,了解您正在处理的警告,并且需要在 awk 解释脚本之前就地扩展 shellvar。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-10
    • 2016-05-17
    相关资源
    最近更新 更多