C++提供了三种浮点类型:float,double和long double.我不经常在我的代码中使用浮点数,但是当我这样做时,我总是被类似无害线路上的警告所困扰
float PiForSquares = 4.0;
Run Code Online (Sandbox Code Playgroud)
问题是文字4.0是双重的,而不是浮动的 - 这很刺激.
对于整数类型,我们有short int,int和long int,这非常简单.为什么C不具有短浮动,浮动和长浮动?在地球上"双重"来自哪里?
编辑:浮动类型之间的关系似乎与整数类似.double必须至少与float一样大,而long double至少与double一样大.没有其他精度/范围的保证.
我想在C++中使用浮点数,如2.25125,以及填充二进制值的int数组,该值用于将浮点数存储在内存中(IEEE 754).
所以我可以取一个数字,最后得到一个int num [16]数组,其二进制值为float:num [0]将是1 num [1]将是1 num [2]将是0 num [3 ]将是1等等......
将int放入数组并不困难,只需获取float的二进制值的过程就是我被困住的地方.你能不能在内存中读取float变量的二进制文件?如果没有,我怎么能用C++做这个呢?
编辑:这种方式进行比较的原因是我想学习在C++中进行逐位运算.
是的,我的意思是说80位.这不是一个错字......
我对浮点变量的经验总是涉及4字节的倍数,如单音(32位),双音(64位)和长双音(我已经看到它被称为96位或128位).这就是为什么当我遇到一些代码来读取和写入AIFF(音频交换文件格式)文件时遇到80位扩展精度数据类型时我有点困惑:选择了一个扩展精度变量来存储采样音轨的速率.
当我浏览维基百科时,我发现上面的链接以及IEEE 754-1985标准摘要中的80位格式的简要提及(但不在IEEE 754-2008标准摘要中).看来,在某些架构上,"扩展"和"长双"是同义词.
我没有遇到的一件事是使用扩展精度数据类型的特定应用程序(当然,AIFF文件采样率除外).这让我想知道:
我正在寻找一种合理有效的方法来确定浮点值(double)是否可以由整数数据类型(long,64位)精确表示.
我最初的想法是检查指数是否0(或更确切地说127).但这不会起作用,因为2.0e = 1 m = 1 ......
基本上,我被卡住了.我有一种感觉,我可以使用位掩码做到这一点,但我现在还没有理解如何做到这一点.
那么我怎样才能检查一个double是否完全可以表示为long?
谢谢
关于sin用表格计算基本函数的文献参考公式:
sin(x) = sin(Cn) * cos(h) + cos(Cn) * sin(h)
Run Code Online (Sandbox Code Playgroud)
其中x = Cn + h,Cn是针对其恒定sin(Cn)和cos(Cn)已被预先计算并在表中可用的,并且,如果以下半乳糖的方法,Cn已被选择为使得两个sin(Cn)和cos(Cn)密切由浮点数近似.数量h接近0.0.此公式的参考示例是本文(第7页).
我不明白为什么这是有道理的:cos(h)然而,它被计算,对于某些值,至少0.5 ULP可能是错误的h,并且因为它接近1.0,这似乎对结果的准确性有极大的影响.sin(x)以这种方式计算.
我不明白为什么不使用下面的公式:
sin(x) = sin(Cn) + (sin(Cn) * (cos(h) - 1.0) + cos(Cn) * sin(h))
Run Code Online (Sandbox Code Playgroud)
然后两个量(cos(h) - 1.0),并sin(h)可以用,很容易做出准确的,因为它们产生接近零的结果多项式来近似.为价值观sin(Cn) * (cos(h) - 1.0), cos(Cn) * sin(h)并为他们的总和仍然很小,其绝对精度,该总和表示,因此,加入这个量的少量ULPS表达sin(Cn)几乎是正确舍入. …
我正在寻找IEEE-754操作的参考实现.有这样的事吗?
C99附件F(IEEE浮点支持)说:
pow(??, y)y> 0时返回+∞而不是奇数.
但是,比方说,( - ∞)0.5实际上有虚数值±∞i,而不是+∞.C99自己sqrt(??)返回NaN并按预期生成域错误.为什么然后pow需要返回+∞?
(大多数其他语言直接使用C库,或者像本例中的Python一样,通过标准复制它所需的行为,因此在实践中这不仅仅影响C99.)
因此,我试图了解更多关于浮点数的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)
不完全是预期的 …
ieee-754 ×10
c ×4
c++ ×3
binary ×2
standards ×2
clang ×1
double ×1
fma ×1
gcc ×1
history ×1
javascript ×1
math ×1
open-source ×1
performance ×1