我有一个问题,我试图重建现有系统中使用的公式,一个输入和一个输出的相当简单的公式:
y = f(x)
经过许多困惑之后,we成功找出了符合我们观察数据点的公式:
正如您所看到的,我们的理论模型非常适合观察数据:
除非我们绘制残差(即y = f(x) - actualY
),否则我们会看到残差中出现一些线:
很明显,这些线是在我们的公式中应用一些中间舍入的结果,但是 where 并不明显。最终意识到原始系统(我们正在尝试进行逆向工程)系统将值存储在中间 Decimal
数据类型中:
我们可以在分数中模拟这个8位精度:
multiply by 128 (i.e. 2^8)
apply the round
divide by 128 (i.e. 2^8)
将上面的等式改为:
这可以显着减少
的剩余误差。
现在,上述所有内容与我的问题无关,除了:
现在我想在使用 Single Precision
浮点数的编程语言(和Excel)中模拟 Double Precision
浮点数。我想这样做是因为我想 这就是我们所需要的。
在上面的示例中,以为原始系统使用的是 Decimal data type with fixed 8-bit fractional precision using 0.5 round-up rules
。然后我必须找到一种用Double
数学模拟该计算模型的方法。现在我认为原始系统正在使用Single
精度数学,我想用Double
进行模拟。
如何使用双精度模拟单精度舍入?
在我目前的模型中,我再次将残差归入常规线性模式 - 这是四舍五入的标志:
问题是,当输入变量变大时,错误变得更大,并且只是可见的。我意识到这很可能是因为所有浮点数都被归一化为IEEE 754“科学记数法”。
即使我错了,我还是想尝试一下。
即使我不想尝试,我仍然会问这个问题
如何使用
Single
模拟Doubles
精确舍入?
在我看来,我仍然可以应用“在8个小数位后舍入”的概念(虽然Single
精度浮点数为24位),只要我可以先< em>“normalize”
1234567898.76543
需要转换为(类似):
1.23456789876543 E-09
然后我可以将我的“轮到第24位”(即2 ^ 24 = 16,777,216)
floor(1.23456789876543E-09 * 16777216 + 0.5) / 16777216;
问题是,我可以应用sign
,abs
,ln
,exp
(或其他函数)的组合,以便我可以“规范化“我的价值,把它绕到第n个二进制位置,然后”反规范“它?
注意:我意识到IEEE表示将二进制1
保留为最高位。我可能不需要复制该行为以获得正确的结果。所以这不是一个交易破坏者,也不是因为它表明整个方法都是失败的。
答案 0 :(得分:8)
你想使用库函数frexp和ldexp,它们是标准的C99函数,并且可以在Lua中使用。
frexp采用浮点数并将尾数与指数分开。得到的尾数是0或者在[0.5,1.0)或(-1.0,0.5)范围之一中。然后你可以以明显的方式删除任何额外的位(floor(mantissa * 2^k)/2^k
用于非负值,例如)。(编辑添加:)最好从ldexp调用中的指数中减去k而不是如图所示进行除法,因为我很确定Lua不能保证2 ^ k是精确的。
ldexp是frexp的反转;您可以使用它将截断的数字重新组合在一起。
我不知道如何在Excel中执行此操作。检查手册:)(编辑添加:)我想你可以通过将数字除以2得到大致相同的效果,得到数字的log 2的上限的幂,然后如上所示进行二进制舍入,然后反转过程以重新创建原始指数。但我怀疑结果偶尔会出现Excel对算术的特殊想法的特殊性。
答案 1 :(得分:5)
使用以下方法可以获得舍入到单精度的大部分效果:
y = x + x * 0x1p29 - x * 0x1p29;
在大多数情况下,这会在y中产生相同的结果,就好像x已经四舍五入为浮点数(32位二进制IEEE 754),然后转换回双精度(64位)。它通过添加一个值(x * 0x1p29)来“推”出有效数字中的某些x,导致第23位舍入,然后减去添加的值。 (0x1p29
是2 29 ,536870912的十六进制浮点数。)
在极少数情况下,它会产生略微不同的结果。如果您只想降低模型中的噪音,这些极少数情况可能会微不足道。如果你想消除它们,那么,你可以找到不大于x的2的最大幂并且加上和减去2 29 ,而不是加上和减去2 29 x。而不是2 29 x。 (为了找到2的幂,你可以取两个对数并取其底线。但是,仍有可能需要补偿的舍入问题。此外,如果输入可能为零或负数,则必须避免取其对数时发生的错误。)
此外,这不会重现单精度次正规或以单精度溢出的数字的行为。
最后,在极少数情况下,计算双精度结果然后舍入到单精度会产生与最初计算单精度结果略有不同的结果,并且没有舍入双精度结果的方法将解决此问题。
答案 2 :(得分:1)
使用这样的代码(C):
double x, y;
/ ... y gets a double value somewhere ... /
x = (double)(float)y;
之后,x(double)将得到一个值,该值是将y舍入为单精度浮点数。
答案 3 :(得分:1)
您可以使用 Excel VBA 中的模块创建自定义功能:
Function SINGLEFLO(Eingang As Double)
Dim MySingle As Single
MySingle = CSng(Eingang)
SINGLEFLO = CDbl(MySingle)
End Function
然后,如果需要将精度限制为SINGLEFLO()
,则可以在所有Excel单元格中使用Single Float
。