>>> (float('inf')+0j)*1
(inf+nanj)
Run Code Online (Sandbox Code Playgroud)
为什么?这在我的代码中造成了一个讨厌的错误。
为什么1乘法身份不给(inf + 0j)?
我读过关于浮点的内容,我知道NaN可能来自操作.但我无法完全理解这些概念是什么.有什么区别?
在C++编程期间可以生成哪一个?作为程序员,我可以编写一个程序来导致sNaN吗?
我知道浮点数是如何表示的,但是还不够,我害怕.
一般问题是:
对于给定的精度(对于我的目的,基数10中的精确小数位数),可以为16位,32位和64位IEEE-754系统表示什么范围的数字?
具体来说,我只对16位和32位数字的范围感兴趣,精确到+/- 0.5(那些位置)或+/- 0.0005(千分位数).
确定给定的浮点数arg是否正常,即既不是零,也不是正常,无限,也不是NaN.
数字为零,无限或NaN很清楚它意味着什么.但它也说低于正常.什么时候是一个数字次正常?
在.NET中运行与双倍乘法相关的快速实验?并阅读了几篇关于C#字符串格式的文章,我认为这样:
{
double i = 10 * 0.69;
Console.WriteLine(i);
Console.WriteLine(String.Format(" {0:F20}", i));
Console.WriteLine(String.Format("+ {0:F20}", 6.9 - i));
Console.WriteLine(String.Format("= {0:F20}", 6.9));
}
Run Code Online (Sandbox Code Playgroud)
将是这个C代码的C#等价物:
{
double i = 10 * 0.69;
printf ( "%f\n", i );
printf ( " %.20f\n", i );
printf ( "+ %.20f\n", 6.9 - i );
printf ( "= %.20f\n", 6.9 );
}
Run Code Online (Sandbox Code Playgroud)
但是C#会产生输出:
6.9
6.90000000000000000000
+ 0.00000000000000088818
= 6.90000000000000000000
Run Code Online (Sandbox Code Playgroud)
尽管我在调试器中显示的值等于6.89999999999999946709(而不是6.9).
与C比较,显示格式要求的精度:
6.900000
6.89999999999999946709
+ 0.00000000000000088818
= 6.90000000000000035527
Run Code Online (Sandbox Code Playgroud)
这是怎么回事?
(Microsoft .NET Framework版本3.51 SP1/Visual …
我的问题是,是否保证所有整数值都具有完美的双重表示.
请考虑以下打印"相同"的代码示例:
// Example program
#include <iostream>
#include <string>
int main()
{
int a = 3;
int b = 4;
double d_a(a);
double d_b(b);
double int_sum = a + b;
double d_sum = d_a + d_b;
if (double(int_sum) == d_sum)
{
std::cout << "Same" << std::endl;
}
}
Run Code Online (Sandbox Code Playgroud)
对于任何架构,任何编译器,任何值a和b?保证这是真的吗?i转换为的任何整数是否double总是表示为i.0000000000000和不表示为,例如,i.000000000001?
我尝试了其他一些数字并且它总是如此,但无法找到关于这是巧合还是设计的任何信息.
注意:这与这个问题(除了语言)不同,因为我添加了两个整数.
看到这段代码:
<html>
<head>
<script src="http://www.json.org/json2.js" type="text/javascript"></script>
<script type="text/javascript">
var jsonString = '{"id":714341252076979033,"type":"FUZZY"}';
var jsonParsed = JSON.parse(jsonString);
console.log(jsonString, jsonParsed);
</script>
</head>
<body>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
当我在Firefox 3.5中看到我的控制台时,jsonParsed的值是:
Object id=714341252076979100 type=FUZZY
Run Code Online (Sandbox Code Playgroud)
即数字四舍五入.尝试了不同的值,相同的结果(数字舍入).
我也没有得到它的舍入规则.714341252076979136舍入为714341252076979200,而714341252076979135舍入为714341252076979100.
编辑:请参阅下面的第一条评论.显然这不是关于JSON,而是关于JavaScript数字处理的东西.但问题仍然存在:
为什么会这样?
我正在阅读Java语言规范中的浮点NaN值(我很无聊).32位float具有此位格式:
seee eeee emmm mmmm mmmm mmmm mmmm mmmm
Run Code Online (Sandbox Code Playgroud)
s是符号位,e是指数位,m是尾数位.NaN值被编码为所有1的指数,并且尾数位不是全0(其将是+/-无穷大).这意味着存在许多不同的可能NaN值(具有不同的s和m位值).
在此,JLS§4.2.3说:
IEEE 754为其单浮点格式和双浮点格式提供了多个不同的NaN值.虽然每个硬件架构在生成新的NaN时返回NaN的特定位模式,但是程序员也可以创建具有不同位模式的NaN以编码例如回顾性诊断信息.
JLS中的文本似乎意味着,例如,结果0.0/0.0具有依赖于硬件的位模式,并且取决于该表达式是否被计算为编译时常量,它依赖的硬件可能是硬件编译Java程序或运行程序的硬件.如果这是真的,这一切似乎都很脆弱.
我运行了以下测试:
System.out.println(Integer.toHexString(Float.floatToRawIntBits(0.0f/0.0f)));
System.out.println(Integer.toHexString(Float.floatToRawIntBits(Float.NaN)));
System.out.println(Long.toHexString(Double.doubleToRawLongBits(0.0d/0.0d)));
System.out.println(Long.toHexString(Double.doubleToRawLongBits(Double.NaN)));
Run Code Online (Sandbox Code Playgroud)
我机器上的输出是:
7fc00000
7fc00000
7ff8000000000000
7ff8000000000000
Run Code Online (Sandbox Code Playgroud)
输出显示没有超出预期.指数位都是1.尾数的高位也是1,对于NaN,它显然表示"安静的NaN"而不是"信号NaN"(https://en.wikipedia.org/wiki/NaN# Floating_point).符号位和尾数位的其余部分为0.输出还显示我的机器上生成的NaN与Float和Double类的常量NaN之间没有差异.
我的问题是,无论编译器或虚拟机的CPU是什么,在Java中都能保证输出,还是真的无法预测?JLS对此很神秘.
如果保证输出0.0/0.0,是否有任何算法生成具有其他(可能依赖于硬件?)位模式的NaN?(我知道intBitsToFloat/ longBitsToDouble可以编码其他NaN,但我想知道其他值是否可以从正常算术中发生.)
后续要点:我注意到Float.NaN和Double.NaN指定了它们的确切位模式,但是在源(Float,Double)中它们是由它们生成的0.0/0.0.如果该划分的结果实际上取决于编译器的硬件,那么在规范或实现中似乎存在缺陷.
我找到了一个相当奇怪但工作的平方根逼近floats; 我真的不明白.有人能解释一下为什么这段代码有效吗?
float sqrt(float f)
{
const int result = 0x1fbb4000 + (*(int*)&f >> 1);
return *(float*)&result;
}
Run Code Online (Sandbox Code Playgroud)
我测试了一下它输出的值std::sqrt()约为1到3%.我知道Quake III的快速反平方根,我想这里有类似的东西(没有牛顿迭代),但我真的很感激它的工作原理.
我最近读了很多关于IEEE 754和x87架构的内容.我正在考虑在我正在研究的一些数值计算代码中使用NaN作为"缺失值",我希望使用信令 NaN将允许我在我不想要的情况下捕获浮点异常继续"缺失值".相反,我会使用安静的 NaN来允许"缺失值"通过计算传播.但是,信号NaN不起作用,因为我认为它们将基于它们上存在的(非常有限的)文档.
以下是我所知道的摘要(所有这些都使用x87和VC++):
标准库提供了一种访问NaN值的方法:
std::numeric_limits<double>::signaling_NaN();
Run Code Online (Sandbox Code Playgroud)
和
std::numeric_limits<double>::quiet_NaN();
Run Code Online (Sandbox Code Playgroud)
问题是我认为信号NaN没有任何用处.如果屏蔽了_EM_INVALID,则其行为与安静NaN完全相同.由于没有NaN与任何其他NaN相当,因此没有逻辑差异.
如果未屏蔽_EM_INVALID (启用异常),则甚至无法使用信号NaN初始化变量:
double dVal = std::numeric_limits<double>::signaling_NaN();因为这会引发异常(信号NaN值被加载到x87寄存器以将其存储到存储器地址).
您可以像我一样思考以下内容:
但是,步骤2会导致信令NaN转换为安静的NaN,因此后续使用它不会导致异常被抛出!那么WTF?!
信号NaN是否有任何实用性或目的?我理解其中一个原始意图是使用它初始化内存,以便可以捕获使用单位化浮点值.
有人能告诉我,如果我在这里遗失了什么吗?
编辑:
为了进一步说明我希望做的事情,这里有一个例子:
考虑对数据向量(双精度)执行数学运算.对于某些操作,我想允许向量包含"缺失值"(假设这对应于电子表格列,例如,其中一些单元格没有值,但它们的存在很重要).对于某些操作,我不希望允许向量包含"缺失值".如果集合中存在"缺失值",也许我想采取不同的行动 - 可能执行不同的操作(因此这不是无效的状态).
这个原始代码看起来像这样:
const double MISSING_VALUE = 1.3579246e123;
using std::vector;
vector<double> missingAllowed(1000000, MISSING_VALUE);
vector<double> missingNotAllowed(1000000, MISSING_VALUE);
// ... populate missingAllowed and missingNotAllowed with (user) data...
for (vector<double>::iterator it = missingAllowed.begin(); it != missingAllowed.end(); ++it) …Run Code Online (Sandbox Code Playgroud) ieee-754 ×10
c++ ×4
nan ×3
precision ×2
c ×1
c# ×1
c++11 ×1
double ×1
formatting ×1
java ×1
javascript ×1
numerical ×1
optimization ×1
python ×1
standards ×1
visual-c++ ×1
x87 ×1