【发布时间】:2021-11-14 23:51:00
【问题描述】:
[编辑 2021-09-26]
对不起!,我不得不承认我在这里问废话,解释如下。我认为我不应该将此作为“答案”发布,而是作为编辑:
我仍然很好奇 0.1 的“double”值如何转换为 long double!
但问题的重点是,使用“双精度”计算的电子表格程序存储值的方式是,计算精度更高的程序会错误地读取它们。我现在 - 只是现在,我瞎了 :-( - 明白它不是!存储一个“双”二进制值,而是一个字符串!
在这个 gnumeric 中,程序犯了很少的错误之一,它使用固定的字符串长度并将'0.1' 存储为'0.10000000000000001',从'0.10000000000000000555xx' 向上取整。 LO Calc 和 Excel 存储 - 我认为更好 - 在往返 'bin -> dec -> bin' 中幸存下来的最短字符串,即'0.1'。这也可以作为更精确的程序的交换。
所以这个问题已经解决了,问题没有“解决”,但我可以解决它。
仍然很好奇:会,如果是的话,哪些步骤会加倍:0 01111111011 (1).1001100110011001100110011001100110011001100110011010
转换为(80 位)长双精度:0 011111111111011 1.10011001100110011001100110011001100110011001100110**10** **00000000000**
或者,如果,如果有哪些(其他)步骤,可以发送至:0 011111111111011 1.10011001100110011001100110011001100110011001100110**01** **10011001101**
[/编辑]
原始问题:
请耐心等待,这个问题一定是老问题了,但我还没有找到答案……我瞎了?,
简而言之:
是否有任何 CPU、FPU 开关、命令、宏、库、技巧或优化的标准代码 sn-p 是 doe 的:'将双精度值转换为长双精度值(具有更好的精度!)并保持相应'十进制值'!而不是“精确但有偏差”的“位值”?
[编辑 2021-09-23]
我发现了一些可以完成这项工作的东西,任何人都可以提出如何“安装”它以及内部的哪些功能可以“调用”以在其他程序(debian linux 系统)中使用它?
Ulf (ulfjack) Adams 在他的“ryu”项目“https://github.com/ulfjack/ryu”中宣布了针对此类问题(打印输出?)的解决方案。他评论说:
'##柳
Ryu 生成保持往返安全的浮点数的最短十进制表示。也就是说,正确的解析器可以恢复准确的原始数字。例如,考虑二进制 32 位浮点数 00111110100110011001100110011010。存储的值正是
0.300000011920928955078125。但是,这个浮点数也是最接近十进制数0.3 的数字,所以这就是 Ryu 输出的内容。'
(恕我直言,它应该是“最接近的 IEEE 浮点数”)
他也宣布该算法“快”,但与其他算法相比可能“快”,计算“最短”与计算固定长度字符串相比“快”不一样?
[/编辑]
假设我有一个电子表格,它以双精度格式存储值,其中的值由于“二进制文件不完全可表示”而偏离其十进制对应值。
例如。 '0.1',我可能将其键入为'0.1' 或给定公式'=1/10',存储的“值”为“双”将是相同的:0 01111111011 (1).1001100110011001100110011001100110011001100110011010 这是appr。
0.10000000000000000555112~ 十进制。
现在我已经稍微调整了我的电子表格程序,它现在可以使用“长双打”。 (我真的!这样做了,它是 gnumeric,不要尝试使用 MS Excel 或 LibreOffice Calc!)。我的系统以及大多数 Intel 硬件上的 80 位格式(1 位符号,15 位指数,64 位尾数,来自标准化的前导“1”存储在位中!(不是“隐式”和“左侧”,如'双打'))。
在新工作表中,我可以愉快地键入 '0.1' or '=1/10' 并得到(估计,无法测试):0 011111111111011 1.100110011001100110011001100110011001100110011001100110011001101
0.100000000000000000001355253~ 十进制,很好:-)
如果我打开我的'旧'文件'公式'!将被重新解释并显示更精确的值,但“值”!'0,1'! 不是!重新诠释。相反 - 恕我直言 - 来自双精度值的位被放入长结构中,构建一个尾数,如
1.1001100110011001100110011001100110011001100110011010**00000000000**
完全保留十进制 -> 二进制(双)转换的舍入误差,再次生成十进制表示:0.10000000000000000555112~
[编辑 2021-09-23]
没有最终深入研究...看起来在某些情况下存储和读取使用字符串,有时“更长的字符串”得到00555112~,而在其他情况下存储一个圆形字符串0,10000000000000001和' long' 版本在加载时会生成0,100000000000000010003120,甚至更糟。
[/编辑]
正如主题中所说,这是一种模棱两可的情况,可以完全保留双位给出的值,或者!将其解释为“四舍五入的占位符”并尝试将其“最初预期的十进制值”取回,但不能同时使用。我在玩'保持十进制值',可以!这样做例如通过特定的四舍五入,但这既复杂又昂贵 - 就计算工作而言。
正如我在过去几周看到的那样,IEEE、CPU 和库开发人员都是高技能人员,他们明智地预见并实施了类似问题的解决方案:
是否有任何“标准”方法、CPU、FPU 或编译器切换,或优化代码 sn-p 这样做?
将双精度值转换为长双精度值(具有更好的精度!)并保留相应的十进制值而不是偏离的“位值”?
如果“否”,有没有人深入研究过这个问题并对我有什么好的建议?
best regards,
b.
【问题讨论】:
-
A
double没有“对应的十进制值”。double中没有信息表明用户最初输入的是“0.1”而不是“0.1000000000000000055511151231257827021181583404541015625”。如果您想添加一些假设,例如用户从未键入超过十个有效数字,然后将由此产生的double转换为由相同数字产生的long double,那么解决方案很简单:将double转换为十进制有效数字(例如,在C 中,sprintf和%.10g),然后转换为long double(strtold)。 -
但是,这种假设是错误的。用户有时会输入更长的数字。
-
感谢@Eric,'sprintf 和 strtold' - 我说得对,这就是'字符串数学'并且非常昂贵的注册。表现? “四舍五入”会更快吗?问题是有没有更好的? '有时输入......' - 是的,当然,但是!我可以确定他们没有输入'0.10000000000000000555112'作为双精度,或者如果!他们这样做了...工作表/转换不接受它,将低于 0.1~125xxx 的所有内容计算为“0.10~0000000”,并用“最近”的 0.1~555111 代替......有了这个结论,我可以削减过头了,问题是哪个是最好的方法...
-
必须补充一点......我记得浮点数、双精度数等的“十进制值”是(关于有多个可能无限长的字符串在做同样的事情)'最短十进制字符串在转换回二进制表示时产生相同的二进制'???从这个意义上说,二进制值具有!一个相应的十进制值(一个!,对于精确中点的极少数情况,最多两个,对于它们,IEEE 默认为二进制偶数('0' 作为最后一位),因此它只有一个!)'对应的十进制',以及 0.10 的所有内容~0055xx' 或类似的会是错误的。 ???
-
找到最接近二进制浮点数的十进制数字,反之亦然是一个复杂的问题。它很“简单”,因为它可以用小学数学来完成,只需将数字执行到所需的小数位数即可。但是,由于
double格式的数字可能超过 10^308,这可能需要数百位数字。如此好的现代二进制到十进制和十进制到二进制例程使用发表在学术论文中的高级算法。研究人员已经找到了处理数字的方法,例如 1.23456789e308,而无需从头开始计算所有内容……
标签: floating-point type-conversion double ieee-754 long-double