我想把这些陷阱用于教育目的.
数值计算中的默认行为的一个常见问题是我们"错过"出现在错误操作中的Nan(或+ -inf).默认行为是通过计算传播,但是一些操作(如比较)打破了链并松开了Nan,并且其余的处理继续而没有在算法的先前步骤中确认奇点.
有时我们有办法对这种事件做出反应:延长一个功能("0/0 = 12在我的情况下"),或者在时域模拟中抛弃一步并尝试其他设置(如预测器,步骤)大小或其他).
所以这是我的问题:你知道将IEEE754陷阱暴露给开发人员的语言吗?我觉得不喜欢乱用ASM.
简而言之:我怎么能执行a+b这样的,因为截断造成的任何精度损失都是零而不是零?
我正在计算一系列浮点值的总和,用于计算集合的样本均值和方差.由于Var(X)= E(X 2) - E(X)2,它足以保持所有数字的运行计数,到目前为止所有数字的总和,以及到目前为止所有数字的平方和.
到现在为止还挺好.
但是,绝对要求E(X 2)> E(X)2,由于浮点精度并非总是如此.在伪代码中,问题是:
int count;
double sum, sumOfSquares;
...
double value = <current-value>;
double sqrVal = value*value;
count++;
sum += value; //slightly rounded down since value is truncated to fit into sum
sumOfSquares += sqrVal; //rounded down MORE since the order-of-magnitude
//difference between sqrVal and sumOfSquares is twice that between value and sum;
Run Code Online (Sandbox Code Playgroud)
对于变量序列,这不是一个大问题 - 你最终会略微低估方差,但这通常不是一个大问题.然而,对于具有非零均值的常数或几乎常数集合,它可能意味着E(X 2)<E(X)2 …
假设我有这个:
float i = 1.5
Run Code Online (Sandbox Code Playgroud)
在二进制文件中,此float表示为:
0 01111111 10000000000000000000000
我打破了二进制代表'signed','exponent'和'fraction'块.
我不明白的是这代表1.5.
一旦减去偏差(127-127),指数为0,隐式前导部分的分数部分为1.1.
1.1如何缩小= 1.5 ???
我想在纯Lua中创建一个函数,它从一个数字生成一个分数(23位),一个指数(8位)和一个符号(1位),这样数字大约等于math.ldexp(fraction, exponent - 127) * (sign == 1 and -1 or 1),然后打包生成的值为32位.
数学库中的某个功能引起了我的注意:
frexp函数将浮点值(v)分解为尾数(m)和指数(n),使得m的绝对值大于或等于0.5且小于1.0,并且v = m*2 ^ N.
请注意,math.ldexp是反向操作.
但是,我想不出任何正确打包非整数的方法.由于此函数返回的尾数不是整数,我不确定是否可以使用它.
有没有什么有效的方法可以做类似于math.frexp()返回整数作为尾数的东西?或者是否有更好的方法在Lua中以IEEE754单精度浮点格式打包数字?
先感谢您.
编辑
我在此提出我所做的功能的(希望)最终版本:
function PackIEEE754(number)
if number == 0 then
return string.char(0x00, 0x00, 0x00, 0x00)
elseif number ~= number then
return string.char(0xFF, 0xFF, 0xFF, 0xFF)
else
local sign = 0x00
if number < 0 then
sign = 0x80
number = -number
end
local mantissa, exponent = math.frexp(number)
exponent = …Run Code Online (Sandbox Code Playgroud) 科学记数法是表达具有明确数量级的数字的常用方法.首先是非零数字,然后是小数点,然后是小数部分和指数.在二进制中,只有一个可能的非零数字.
浮点数学涉及隐含的第一个数字等于1,然后尾数位"跟随小数点".
那么为什么frexp()将小数点放在隐含位的左边,并返回[0.5,1]中的数字而不是像科学符号那样的[1,2]?是否有一些溢出要小心?
实际上,它比IEEE 754/ISO 60559规定的偏差值减去一个以上.在硬件中,这可能会增加XOR的附加值.考虑到在许多情况下恢复正常将需要另一个浮点运算,这似乎是一个相当弱的论点.
我使用的是Microchip的XC32编译器,它基于标准的C编译器.
我正在从RS485网络上的设备读取32位值并将其存储在unsigned long中,我将其命名为DWORD.
即
typedef DWORD unsigned long;
Run Code Online (Sandbox Code Playgroud)
就目前而言,当我将此值转换为float时,我得到的值基本上是它的整数表示的浮点版本,而不是正确的IEEE-754解释浮点数.
即
DWORD dword_value = readValueOnRS485();
float temp = (float)dword_value;
Run Code Online (Sandbox Code Playgroud)
这里,dword_value将以十六进制格式表示为0x4366C0C4,作为十进制将表示为1130807492,因此对浮点数的类型转换只是给我1.130807492*10 ^ 9或1130807492.0这不是我想要的.
我想要单精度IEEE-754表示,它给我一个浮点值230.75299072265625
显然,对浮动进行类型转换对我来说不起作用.我需要一种可以转换此形式的方法.我在XC32库中看了一遍,但找不到任何东西.
有没有人知道一个预定义的方法,为我正确地做出这种解释?或者可能有一些建议的方法我可以写?我试图避免为这个特定任务编写自己的代码,因为我担心如果C已经有了这个功能,我找不到有效的解决方案.
有趣的是,如果我对char*执行此操作,则该值将在char*上正确表示为230.75:
sprintf(random_char_pointer, "%.2f, dword_value);
Run Code Online (Sandbox Code Playgroud)
在这里打印random_char_pointer到屏幕给我230.75所以sprintf必须正确处理解释.因此我假设C中已经存在某些东西.有人可以帮忙吗?
我一直认为,测试NANvia 之间几乎没有区别
x!=x要么
std::isnan(x)但是,gcc为这两个版本提供了不同的汇编程序(在godbolt.org上直播):
;x!=x:
ucomisd %xmm0, %xmm0
movl $1, %edx
setne %al
cmovp %edx, %eax
ret
;std::isnan(x)
ucomisd %xmm0, %xmm0
setp %al
ret
Run Code Online (Sandbox Code Playgroud)
但是,我很难理解这两个版本.我天真的尝试编译std::isnan(x)将是:
ucomisd %xmm0, %xmm0
setne %al ;return true when not equal
ret
Run Code Online (Sandbox Code Playgroud)
但我必须遗漏一些东西.
根据标准ES 将数字实现为 IEEE754 双倍。
每https://www.binaryconvert.com/result_double.html?decimal=053055050054055049056048053048053054056053048051050057054和其他编程语言https://play.golang.org/p/5QyT7iPHNim它看起来像5726718050568503296值可以精确表示不失精度。
为什么它在 JS 中丢失了 3 个有效数字(在最新的稳定版 google chrome 和 firefox 中转载)
这个问题最初是从golang 中的复制 javascript 不安全数字触发的
该值在双 IEEE754 中绝对可以表示,请参阅 Go 中如何将裸位转换为 float64:https : //play.golang.org/p/zMspidoIh2w
有人刚刚问为什么sum(myfloats)不同sum(reversed(myfloats))。很快就被骗到浮点数学坏了吗?并删除。
但这让我很好奇:仅仅通过以不同的顺序求和,我们可以从很少的浮点数中得到多少个不同的总和?使用三个浮点数,我们可以得到三个不同的总和:
>>> from itertools import permutations
>>> for perm in permutations([0.2, 0.3, 0.4]):
print(perm, sum(perm))
(0.2, 0.3, 0.4) 0.9
(0.2, 0.4, 0.3) 0.9000000000000001
(0.3, 0.2, 0.4) 0.9
(0.3, 0.4, 0.2) 0.8999999999999999
(0.4, 0.2, 0.3) 0.9000000000000001
(0.4, 0.3, 0.2) 0.8999999999999999
Run Code Online (Sandbox Code Playgroud)
我相信加法对于浮点数来说是可交换的(即a + b == b + a)。我们对第一对相加有三个选择,然后对第二个相加有一个“选择”,所以三个和是我们仅用三个值就能得到的最多结果。
我们可以得到三个以上具有四个值的不同总和吗?经过一些实验,我没有发现这样的情况。如果我们不能:为什么不呢?如果可以的话:有多少?五有多少?
正如埃里克刚刚指出的,对于三个以上的值,除了从左到右求和之外,还有不同的可能性,例如(a+b) + (c+d)。我对任何添加数字的方式感兴趣。
注意我说的是 64 位浮点数(我是 Python 爱好者,我知道在其他语言中它们通常被称为双精度浮点数)。
是否有任何定义如何在编译时计算的浮点值在 C 或 C++ 中舍入?Fe 当我有double d = 1.0 / 3.0;? 即在编译时进行什么样的舍入。
是否定义了运行时线程的默认舍入模式(C99's / C++11's fegetround()/ fesetround())?
后面的配置参数中是否也包含四舍五入到整数值?我知道nearbyint(),但这被指定为绑定到可以通过设置的舍入参数fesetround()。我担心的是直接转换为整数。