如果有效数字的最低有效位被(/)设置为随机值,那么对浮点数学有什么影响?
说明:
语言PicoLisp使用一个结构分配所有值,该结构由两个“机器字”组成。在32位系统上,这意味着单元是两个32位指针或整数的八字节结构。单元格与其大小对齐,这意味着至少字的最低三位可以自由地用作类型和GC标签数据。
PicoLisp极简主义。语言缺乏的(许多)事物之一是对浮点数的任何支持,而是完全依赖于文档称为“缩放的固定点”表示。我认为尝试添加浮点支持会很有趣。
在32位系统上,64位浮点数可以整齐地放在一个单元格内,这很方便地说分配系统几乎相同,除了一个小问题:双重使用所有64位。但是GC期望使用位0作为GC标记位。天真地进行,在每个收集周期后,位0将被设置为零,而不管双倍中实际存储的是什么值。
(这假设大小和字节顺序都正确排列。假设他们这样做的目的;如果他们不这样做那么整个问题完全无关紧要,必须使用不同的策略。)< / p>
那么:对于通用数学,使用硬件浮点运算有多少问题?
如果它所做的只是减少双倍精度,那么我认为这实际上并不是一个问题:只要它被记录为解释器中的浮点数学不是' t与用户期望的一样精确,如果他们需要严格准确的行为,他们应该回到定点或库或其他东西。我对它的直观理解是,应该是这种情况,因为它是最不重要的一点(当你转换为字符串时甚至不显示......?)。
另一方面,浮点是,呃,巫术。这种小小的摆弄是否会严重影响数学的有用性或产生任何类型的一致结果的能力?
(我已经考虑过分配器的其他几种实现方式。我特别感兴趣的是这个策略是否具有愚蠢性,因为它是最简单的,我很懒。)
答案 0 :(得分:2)
只要外部代码总是将值视为低位已经四舍五入,并且您通过将尾数四舍五入到最接近的偶数值来执行此操作,对于正常的计算,这是可以的。
也就是说,对于结尾的尾声:
00
:什么都不做
10
:什么都不做
01
:从尾数中减去1
11
:在尾数上加1(在溢出时,你需要增加指数并清除尾数)
如果你与舍入不一致并且只是丢掉低位,你会在计算中引入一个非常小的向下偏差。甚至是朝着解决这种向下偏见的方式迈进。
小心+/-无穷大,因为设置低位将把它们变成NAN,这很难处理(突然你的所有比较操作都开始失败)。
答案 1 :(得分:2)
StilesCrisis计划提出了原因双舍入,通常被视为bad thing。
我想提出另一个选择:
使用每个PicoLisp浮点显示和计算,就好像它比它大2 512 倍。这意味着双加法和减法几乎保持不变,乘法和除法需要一个便宜的调整,而其他操作(库调用)需要两次调整,一次调整,一次调整。
每次操作后,检查溢出(现在更频繁地发生,每当偏差结果高于1.0时)。
如果你这样做,而不是借用有效数字的最低有效位,你实际上是在借用指数的最高位。这需要一些位移动来加载和存储浮点数,但这对于使用该系统的程序员来说更容易解释,并且为类似IEEE 754的属性设计的算法将继续工作(除非它们现在溢出)。
代码可能如下所示lightly tested implementation。另一个上下文中的类似实现是此blog post的对象,它提供了更多解释。
void smalldouble_to_cell(void*p, double d)
{
union u u;
u.d = d;
unsigned long long rest = u.u & 0x7fffffffffffffff;
unsigned long long packed;
if (rest > 0x7ff0000000000000)
/* NaN */
packed = u.u & 0xfffffffffffffffe;
else
{
unsigned long long sign = u.u & 0x8000000000000000;
if (rest >= 0x3ff0000000000000)
rest = 0x3ff0000000000000;
packed = sign | (rest << 1);
}
memcpy(p, &packed, 8);
}
void double_to_cell(void *p, double d)
{
smalldouble_to_cell(p, ldexp(d, -512));
}
答案 2 :(得分:1)
有效数字的最低有效位的变化通常具有您认为具有的效果 - 它将改变该数字的最低有效位。
但是你会遇到一些特殊情况的问题。
[根据Eric Postpischil对我之前的文本的准确批评进行编辑:调整零表示只会导致非常小的非正规数]
你会看到类似于加号或减号无限编码的相反问题。 Inifinity使用最大可能指数和零有效数进行编码。如果有效数据被修改,那么无限将变成NaN。