C99附件F(IEEE浮点支持)说:
pow(??, y)y> 0时返回+∞而不是奇数.
但是,比方说,( - ∞)0.5实际上有虚数值±∞i,而不是+∞.C99自己sqrt(??)返回NaN并按预期生成域错误.为什么然后pow需要返回+∞?
(大多数其他语言直接使用C库,或者像本例中的Python一样,通过标准复制它所需的行为,因此在实践中这不仅仅影响C99.)
当我在支持软件浮动仿真(硬件浮点禁用)的32位powerpc内核中运行以下C++程序时,我得到了错误的条件评估.有人可以告诉我这里有什么潜在的问题吗?
#include <stdio.h>
int main() {
int newmax = 1;
if ((newmax + 0.0) > 256) {
printf("\nShouldn't be here\n");
} else {
printf("\nShould be here\n");
}
}
Run Code Online (Sandbox Code Playgroud)
编译:
powerpc-linux-g++ -msoft-float -c floating.cxx
powerpc-linux-g++ -o floating floating.o
Run Code Online (Sandbox Code Playgroud)
目标系统中的输出:
[linux:/]$ ./floating
Shouldn't be here
Run Code Online (Sandbox Code Playgroud) 因此,我试图了解更多关于浮点数的IEEE 754标准中定义的非规范化数字.由于Google搜索结果,我已经阅读了几篇文章,并且我已经阅读了几篇StackOverFlow帖子.但是我还有一些问题没有答案.
首先,回顾一下我对Denormalized float的理解:
具有较少精度位的数字,并且比标准化数字更小(数量级)
实质上,非规范化浮点数能够表示可以用任何浮点值表示的SMALLEST(幅度)数.
这听起来不对吗?还有什么呢?
我读过:
使用非规范化数字会在许多平台上带来性能成本
对此有何评论?
我也读过其中一篇文章
一个应该"避免规范化和非规范化数字之间的重叠"
对此有何评论?
在IEEE标准的一些演示中,当呈现浮点范围时,排除非规格化值并将表标记为"有效范围",几乎就像演示者正在思考"我们知道非规范化数字CAN表示可能的最小浮动点值,但由于非规范化数字的某些缺点,我们选择将它们从更适合常见使用场景的范围中排除" - 好像非常规化数字不常用.
我想我一直认为在大多数情况下使用非规范化数字并不是一件好事?
如果我必须自己回答这个问题,我会想:
使用非规格化数字是好的,因为您可以表示可能的最小(数量级)数字 - 只要精度不重要,并且您不将它们与标准化数字混合,并且应用程序的最终性能符合要求.
使用非规范化数字是一件坏事,因为大多数应用程序不需要如此小的表示 - 精确损失是有害的,并且你可以通过将它们与标准化数字混合来轻松地射击自己,并且性能不值得花费在多数情况下.
对这两个答案有何评论?还有哪些我可能会丢失或不理解非规范化数字?
使用GCC 5.3,以下代码符合 -O3 -fma
float mul_add(float a, float b, float c) {
return a*b + c;
}
Run Code Online (Sandbox Code Playgroud)
生成以下程序集
vfmadd132ss %xmm1, %xmm2, %xmm0
ret
Run Code Online (Sandbox Code Playgroud)
Clang 3.7带-O3 -mfma产品
vmulss %xmm1, %xmm0, %xmm0
vaddss %xmm2, %xmm0, %xmm0
retq
Run Code Online (Sandbox Code Playgroud)
但Clang 3.7与-Ofast -mfmaGCC生成的代码相同-O3 fast.
我很惊讶GCC的确如此,-O3因为从这个答案来看
除非允许使用宽松的浮点模型,否则不允许编译器融合分离的加法和乘法.
这是因为FMA只有一个舍入,而ADD + MUL有两个舍入.因此,编译器将通过融合违反严格的IEEE浮点行为.
但是,从这个链接说
无论FLT_EVAL_METHOD的值如何,任何浮点表达式都可以收缩,即,计算好像所有中间结果都具有无限范围和精度.
所以现在我感到困惑和担忧.
-O3?__STDC_IEC_559__不是一个矛盾吗?由于FMA 可以在软件中进行仿真,因此似乎应该有两个用于FMA的编译器开关:一个用于告诉编译器在计算中使用FMA,一个用于告诉编译器硬件具有FMA.
显然,这可以通过选项进行控制-ffp-contract.对于GCC,默认是-ffp-contract=fast和Clang不一样.其他选项例如 …
当我在控制台中运行时,0.1 + 0.2结果是0.30000000000000004.所以我试着自己计算一下.以下是我采取的步骤.
1)表示0.1为IEEE754双:
0.1 = 0 01111111011 1001100110011001100110011001100110011001100110011010
Run Code Online (Sandbox Code Playgroud)
2)表示0.2为IEEE754双:
0.2 = 0 01111111100 1001100110011001100110011001100110011001100110011010
Run Code Online (Sandbox Code Playgroud)
这里的计算应该是正确的,因为我已经使用我的自定义函数检查了它们,该函数显示了JavaScript如何存储数字.
3)将两个数字转换为科学记数法:
0.1 = 1.1001100110011001100110011001100110011001100110011010x 2-4
0.2 = 1.1001100110011001100110011001100110011001100110011010x 2-3
现在由于指数数字不同,让我们调整0.2为-4:
0.2 = 0.11001100110011001100110011001100110011001100110011010x 2-4
4)添加它们:
1.1001100110011001100110011001100110011001100110011010
+ 0.1100110011001100110011001100110011001100110011001101
------------------------------------------------------
10.0110011001100110011001100110011001100110011001100111
Run Code Online (Sandbox Code Playgroud)
所以总和是:
10.0110011001100110011001100110011001100110011001100111x 2-4
5)将其标准化:
1.00110011001100110011001100110011001100110011001100111x 2-3
6)在小数点后将其四舍五入:
1.1100110011001100110011001100110011001100110011010000x 2-3
删除指数后,我最终得到以下结果数:
0.001110011001100110011001100110011001100110011001101
Run Code Online (Sandbox Code Playgroud)
当我使用此计算器将其转换为十进制时,它显示:
0.225000000000000088817841970012523233890533447265625
Run Code Online (Sandbox Code Playgroud)
不完全是预期的 …
对于浮点运算(IEEE754,如果存在混淆)有什么好的做法和不做什么,以确保良好的数值稳定性和结果的高精度?
我知道有些人不喜欢减去相似数量的数量,但我很好奇其他有什么好的规则.
有多少可表示彩车之间是否有0.0和0.5?又有多少表现的彩车之间是否有0.5和1.0?我对它背后的数学更感兴趣,我需要答案floats和doubles.
我实现了W3s推荐的算法,用于将SVG路径弧从端点弧转换为中心弧并返回 Haskell.
type EndpointArc = ( Double, Double, Double, Double
, Bool, Bool, Double, Double, Double )
type CenterArc = ( Double, Double, Double, Double
, Double, Double, Double )
endpointToCenter :: EndpointArc -> CenterArc
centerToEndpoint :: CenterArc -> EndpointArc
Run Code Online (Sandbox Code Playgroud)
但我无法通过这个属性:
import Test.QuickCheck
import Data.AEq ((~==))
instance Arbitrary EndpointArc where
arbitrary = do
((x1,y1),(x2,y2)) <- arbitrary `suchThat` (\(u,v) -> u /= v)
rx <- arbitrary `suchThat` (>0)
ry <- arbitrary `suchThat` (>0)
phi <- choose (0,2*pi)
(fA,fS) …Run Code Online (Sandbox Code Playgroud) 当我调试代码时,我发现GCC和Clang都产生了纳米,0.0/0.0这正是我所期待的,但GCC产生一个nan,符号位设置为1,而Clang将其设置为0(与ICC一致,如果我记得正确).
现在显然两种形式都是允许的,但我一直想知道为什么0.0/0.0GCC输出会产生"负面"结果(打印出来-nan),并-(0.0/0.0)给出"正面"结果?更令人困惑的是,-0.0/0.0再次"消极".这是一个不断折叠的怪异吗?
编辑
实际上,它是恒定的折叠,使其成为一个积极的纳米.如果我在运行时强制执行计算,我会在GCC和Clang上得到负值
volatile float zero = 0.0;
std::cout << (zero/zero); // -nan
Run Code Online (Sandbox Code Playgroud)
请问有人对此有所了解吗?x86 FPU上的符号位是否设置为1?
在回答我建议的问题时-ffast-math,评论指出这是危险的.
我个人的感觉是,在科学计算之外,没关系.我还认为严肃的财务应用程序使用固定点而不是浮点数.
当然,如果你想在你的项目中使用它,最终的答案是在你的项目上测试它,看看它对它有多大影响.但我认为,尝试并具有此类优化经验的人可以给出一般答案:
可以ffast-math在正常项目中安全使用吗?
鉴于IEEE 754浮点具有舍入误差,假设您已经生活在不精确的计算中.
这个答案特别启发了这样一个事实:-ffast-math除了重新排序操作会导致稍微不同的结果(不检查NaN或零,禁用签名零只是为了说明一些),但我没有看到效果是什么其中最终将是一个真实的代码.
我试着想到浮点的典型用法,这就是我提出的:
和学校项目,但这些并不重要.
ieee-754 ×10
c ×4
c++ ×3
gcc ×2
standards ×2
binary ×1
clang ×1
fma ×1
haskell ×1
javascript ×1
math ×1
nan ×1
optimization ×1
performance ×1
powerpc ×1
quickcheck ×1
svg ×1