【问题标题】:C++ calculation with type "long"“long”类型的 C++ 计算
【发布时间】:2013-01-05 23:30:25
【问题描述】:

我有一个内联函数进行频率到周期的转换。计算精度必须使用 long 类型,而不是 double 类型。否则,可能会导致一些舍入错误。然后该函数将结果转换回 double。我想知道在下面的代码中,哪一行会将计算保持在 long 类型中。无论参数栏是 100、100.0 还是 33.3333。

double foo(long bar)
{
  return 1000000/bar;
  return 1000000.0/bar;
  return (long)1000000/bar;
  return (long)1000000.0/bar;
}

我自己试过了,第 4 行有效。但只是想知道这种情况下类型转换的概念。

编辑:

其中一个错误是 1000000/37038 = 26,而不是 26.9993。

【问题讨论】:

  • 请注意,存储在 double 中的整数值不会出现舍入错误,除非它超出尾数的范围,通常为 2**52。
  • bar 在作为 long 传递时不能为 33.3333。它将转换为 33。
  • bar 不可能是100.033.3333。您应该使用 1000000L 作为常数。
  • PS:您能否详细说明您期望的舍入误差?要提供建议,您必须说明传递给函数的值范围以及您愿意接受的舍入误差。根据实际系统,可以选择使用 long double 类型或编译器支持的其他扩展精度类型 (en.wikipedia.org/wiki/Long_double)。但是请注意,MS VC++ long double 中的 AFAIK 只是同义词 4 double,在这方面无济于事。
  • @Stan:如果您进行整数运算(这就是您所说的,“必须使用类型long”),那么您将得到整数结果:26,而不是 26.9993。如果您想要非整数结果,那么您需要使用浮点(或有理数,或其他)算术,而不是整数;例如,return 1000000/double(bar);

标签: c++ types precision


【解决方案1】:

你提出的这个问题没有意义。

bar是整数类型,所以1000000/bar肯定小于1000000,可以用double1精确表示,所以没办法以积分算术执行所有计算可以提供更好的精度 - 实际上,您将获得整数除法,在这种情况下,对于 bar 的任何值,它较少精确,因为它会截断小数部分。在longdouble 的转换中出现问题的唯一方法是在bardouble 的转换中,但如果它超出double 的范围,则除法的最终结果将为0,就像整数算术一样。

仍然:

1000000/bar

longs 之间进行除法:1000000 是intlong,取决于平台,barlong;如有必要,第一个操作数被提升为long,然后执行整数除法。

1000000.0/bar

doubles 之间进行除法:1000000.0double 文字,因此bar 在除法之前被提升为double

(long)1000000/bar

相当于第一个:演员优先于除法,并强制1000000longint)成为longbar 是一个long,在longs 之间进行除法。

(long)1000000.0/bar

等价于前一个:1000000.0double,但你将其转换为 long,然后执行整数除法。


  1. C++ 标准将此事委托给 C 标准,要求 doubles (DBL_DIG) 的尾数至少为 10 位十进制数字,并且在开始之前至少将 10**37 作为可表示的 10 次幂超出范围 (DBL_MAX_10_EXP)(C99,附件 E,¶4)。

【讨论】:

  • "可以用双精度精确表示"
  • @Tinctorious:“which”指的是1000000可以double精确表示。除法的结果可能准确表示也可能不准确,但在这种情况下,double 除法肯定比long 除法(截断小数部分)具有更好的精度。
  • @Tinctorius 他说1000000可以完全表示为double。形式上,我不确定它是否受到 C++ 标准的保证,但我从未听说过不正确的实现。
  • 我的立场是正确的。也许我应该花更多的时间来阅读……单词;)
  • @JamesKanze:看来是有保证的,见更新后的脚注。
【解决方案2】:

第一行(第三行更详细)将作为long 进行数学运算(在 C++ 中总是截断任何结果),然后将整数值作为双精度值返回。我不明白您在关于 bar33.3333 的问题中所说的内容,因为这不可能是 long 值。

【讨论】:

    【解决方案3】:
    return 1000000/bar;
    

    这将做一个很长的数学。

    return 1000000.0/bar;
    

    这将作为一个双重计算。

    return (long)1000000.0/bar;
    

    这相当于第一个 -- 1000000.0 是一个双精度数,但是你在除法之前将它转换为 long,所以除法将在 long 上完成。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-07
      • 1970-01-01
      • 2011-09-13
      • 1970-01-01
      • 2013-09-01
      • 1970-01-01
      相关资源
      最近更新 更多