捕捉浮点数的精度损失
Posted
技术标签:
【中文标题】捕捉浮点数的精度损失【英文标题】:Catching loss of precision in floating numbers 【发布时间】:2021-05-09 03:12:09 【问题描述】:我正在用 C 编写一个小计算器来准备考试。 我知道 double 比 float 更精确,因为它为指数保留 11 位,为有效数保留 53 位。 当涉及到整数时,我可以执行以下操作来捕获上溢/下溢。
int sum(int a, int b, int *res)
if((b > 0) && (a > INT_MAX + b))
return OVERFLOW_ERROR;
else if((b < 0) && (a < INT_MAX + b))
return UNDERFLOW_ERROR;
else
*res = a + b;
return (EXIT_SUCCESS);
当涉及到双倍时,如果数字太高,控制台会给你“inf”或“-inf”,无论如何这都不算太糟糕。 AFAIK,浮点数溢出,当它们失去精度时
所以,我的问题是,您如何处理精度损失?你能让它们“精确”吗? 他们什么时候会失去精度?
【问题讨论】:
使浮点数始终精确需要无限量的 RAM。 浮点计算总是“丢失精度”。 其中一个可能会有所帮助:google.com/search?q=floating+point+precision 精度是指有效数字中的位数——它们可以表示值的精细度。准确度是接近理想结果。您的计算可能会失去准确性,但它们不会失去精度,除非您转换为不太精确的格式,或者您的计算机坏了,或者您在指数范围的边缘附近进行计算,因此低位低于可表示的值。 大多数浮点算法的设计都是为了容忍一些精度损失,而且大多数都无法避免。在有限的情况下,可以特别小心地使用浮点数进行精确计算。这不太可能是您想要学习的偶然使用浮点的课程。此外,硬件通常允许为浮点异常启用陷阱,因此您可以为产生不精确结果的操作启用陷阱。对此的软件支持并不总是很好。即使它可用,启用它也可能会导致程序的其他部分出现陷阱。 【参考方案1】:我已经有一段时间没有正确看待这个问题了,但听起来你混淆了你的术语 - 溢出(数值变得太大)与精度损失(切断部分有效数字)不同。
IIRC,在转换为较短的浮点格式或浮点数变得低于正常/非规范化时会发生精度损失,因此如果您真的想要最大的精度,请使用long double
(或查看您的编译器是否支持更广泛的浮点格式)并在计算的每个阶段检查次正规数。除非您知道您只处理可以精确表示的数字(例如 0.5、0.25、0.125 等)并且不要做疯狂的事情,否则您不能使任何浮点数/计算“绝对精确”将两个完全不同的量级相加。
通常,处理这些类型的数字错误非常复杂,并且特定于正在完成的计算 - 例如你可以重新安排一个方程,这样你就可以避免减去两个值非常接近的数字,这样你就不会lose significance。
如果您还没有看到它,What Every Computer Scientist Should Know About Floating-Point Arithmetic 是一篇很棒的免费文章,我强烈推荐Numerical Computing with IEEE Floating Point Arithmetic 阅读。
【讨论】:
【参考方案2】:如果您想要更精确地进行计算,我可以推荐您使用libgmp.a
或一些类似的库。我无法想象你将要使用它的环境,除了密码学或获得越来越多的小数点,但你有一些库可以让你扩展计算机自然精度的能力。
free42 中有一个示例,它是对 hp-42s 袖珍计算器的模拟(由 Swissmicros 在其袖珍计算器系列中实现 ---see here, for info),它们使用 128 位浮点数,精度为 32十进制数字。
但是精度的提高有一个代价(嗯,不是简单的计算器)是运算必须在软件中解决,不再有机器指令来乘以两个浮点数。每个基本操作都必须在软件中解决,这会减慢整体计算速度。
【讨论】:
以上是关于捕捉浮点数的精度损失的主要内容,如果未能解决你的问题,请参考以下文章