C++和往返数字中的舍入
Rounding in C++ and round-tripping numbers
我有一个类,它在内部将不动点中的一些量表示为32位整数,分母有些任意(既不是2的幂,也不是10的幂)。
对于与其他应用程序的通信,数量在输出时转换为纯旧的双倍,在输入时转换为双倍。作为类内的代码,它看起来像:
int32_t quantity;
double GetValue() { return double(quantity) / DENOMINATOR; }
void SetValue(double x) { quantity = x * DENOMINATOR; }
现在我需要确保,如果我将某个值输出为double并将其读回,我将始终得到相同的值。即
x.SetValue(x.GetValue());
将永远不会改变x.quantity
(x
是包含上述代码的类的任意实例)。
双精度表示有更多的位数,所以它应该是可能的。但几乎可以肯定的是,上面简单的代码不会是这样。
- 我需要使用什么舍入以及
- 我如何找到关键的潜在拐角案例来测试舍入是否确实正确
当你转换为双精度时,任何32位都会被精确地表示,但当你除以然后乘以任意值时,你会得到一个相似的值,但并不完全相同。每次操作最多应该损失一位,这意味着在返回int之前,double将几乎相同。然而,由于int强制转换是截断,当非常小的错误将2.000变为1.999时,您将得到错误的结果,因此您需要在强制转换前执行一个简单的舍入任务。
如果您有C++11,您可以使用std::lround()
,否则您可以编写自己的舍入函数。
在这里,您可能不太关心公平性,所以常见的int(doubleVal+0.5)
将适用于积极因素。如果看起来很可能,你有消极的一面,试试这个:
int round(double d) { return d<0?d-0.5:d+0.5; }
您描述的问题与使用不同基数在二进制和十进制表示之间转换时存在的问题相同。至少,如果你想让double
表示法很好地近似于原始值,它是存在的(否则,你可以将32位的值与固定分母相乘,并将结果存储在double
中)。
假设您希望double
表示与实际值很好地近似,则转换是不平凡的!从内部表示到double
的转换可以使用Dragon4("如何准确打印浮点数",Steele&White)或Grisu。可以使用Bellerophon("如何准确读取浮点数",Clinger)进行反向操作。不过,这些算法并不完全是琐碎的。。。
- C++将浮点指针值舍入为小数位数
- Boost::posix_time::ptime舍入到给定的分钟数
- 浮点定向舍入和优化
- 为什么输出精度没有正确舍入?
- 使用设置精度时如何阻止数字向上舍入?
- 如何在使用 MPFR 时在提升多精度中设置舍入模式
- OpenCV 细分一致的 Rect2f 到 Rect2i 舍入
- C++ 中的舍入函数
- 在特征中将低于特定阈值的数字舍入为零
- istringstream对长数字进行舍入-如何防止这种情况发生
- 如何将数字向上舍入到下一个整数
- C++和往返数字中的舍入
- C++舍入数字,不带上限或下限
- C++数字未正确舍入
- 使用 4/5 舍入规则对数字进行舍入
- 当数字变小的时候,long会加倍舍入吗
- 误差C++舍入数字 - 表达式必须具有整数或枚举类型
- 用两个小数求3个数字的平均值(不舍入!)
- 在c++中,如何使用iostream和iomanip在不显示数字的情况下进行舍入?
- 将任意长度的浮点值舍入为n位数字