C 非法浮点值
我目前正在开发一个嵌入式微控制器,并使用一个定制的printf例程。该工具链是AVR32体系结构的GCC工具链 我的问题是,在第二次调用vsnprintf或类似命令时,CPU会进入异常状态 我从支持部门得到的答复是: 我们找不到这种行为的任何明显原因。但是,通过逐字节写入来创建浮点溢出条件是不安全的。我们无法确保由此产生的值,建议使用“FLT_MAX”进行检查C 非法浮点值,c,exception,gcc,C,Exception,Gcc,我目前正在开发一个嵌入式微控制器,并使用一个定制的printf例程。该工具链是AVR32体系结构的GCC工具链 我的问题是,在第二次调用vsnprintf或类似命令时,CPU会进入异常状态 我从支持部门得到的答复是: 我们找不到这种行为的任何明显原因。但是,通过逐字节写入来创建浮点溢出条件是不安全的。我们无法确保由此产生的值,建议使用“FLT_MAX”进行检查 现在我想知道:什么是“非法”浮点值?难道所有的位组合不应该至少代表某个值吗?如果相关:sizeof(float)是4个字节 我没有研究A
现在我想知道:什么是“非法”浮点值?难道所有的位组合不应该至少代表某个值吗?如果相关:sizeof(float)是4个字节 我没有研究AVR32,但是“非法”浮点值,通常浮点(单精度算术)是数值方法中的重要主题。浮点数的最大值为:
FLT_MAX = 3.40282e+38
但float也有对浮点值的限制。越接近零,可以指定的浮点数就越多
例如:
[1,2]之间的最小值是1.19209e-07
(它是2^-23),也称为macheps(机器ε(float.h中的FLT_ε))
[2,4]之间的最小值为2*1.19209e-07
=2*2^-23
它也适用于订单端:
[1/2,1]之间的最小值为2^-24
为什么会这样?
让我们将数字定义为beforedot.afterdot
数字越大,在点number之前写入所需的位数就越多,而simmetric表示的位数就越少
总之:
浮动的最小值:1.0842e-19
浮动最大值:3.40282e+38
汇总
我建议您打印浮点值的位,就像它们是十六进制整数一样,如下面的代码所示,这样您就可以分析这些位,看看它们是否包含您试图计算的值,或者是否由于某些错误而被不正确地修改
细节
“浮点硬件符合基于IEEE 754浮点标准的C标准的要求。”后一条款是错误的;C标准不是基于IEEE 754。C标准确实规定了与IEEE 754的绑定(通过名称IEC 60559)作为C实现的可选功能,我将假定您使用的AVR32 CPU模型在某种程度上符合IEEE 754
IEEE 754中没有“非法”值。有些值不代表数字,其中一些值旨在引起异常。这种值称为NaN(表示“非数字”)。有静默NaN和信令NaN。静默NaN旨在以静默方式通过操作,产生NaN结果。例如,3+NaN
应产生NaN
。信令NaN旨在导致异常,这可能导致程序控制的更改(例如信号或程序中止)
上面引用的技术参考手册还说“不提供信号NaN,所有NaN均为非信号(安静)。”
一个好的vsnprintf
例程应该接受安静的NaN值进行打印,并且应该通过生成诸如“NaN”之类的字符串对它们进行格式化。当传递一个信号NaN进行格式化时,我想格式化它或生成一个异常可能是合理的
我想您从支持部门收到的信息是,您的软件创建了某种NaN,而vsnprintf
无法处理这些问题。从措辞上看,我认为他们的反应是推测性的
如果您是通过汇编字节来创建浮点值,那么如果软件中出现错误,您可能在无意中创建了NaN。我建议您通过使用vsnprintf
打印浮点值的字节来调试此操作,而不是使用浮点格式说明符打印它
如果您使用的GCC版本具有GCC的常见功能,并且实现中的无符号int
为32位,则可以使用以下方法将32位浮点值x
的位格式化为十六进制值:
vsnprintf(Buffer, BufferLength, "0x%x",
(union { float f; unsigned int u; }) {x} .u);
第二行使用复合文字将值x
放入并集,并将其字节重新解释为无符号int
。(这在C中是一种受支持的重新解释对象字节的方法。许多人使用指针别名,如果使用适当的标志,这在GCC中是有效的,但C标准通常不支持。另一种受支持的方法是复制字节,如unsigned int u;memcpy(&u,&x,sizeof u);
)
一旦您看到浮点
中的位是什么,您可以从IEEE 754标准中的信息或使用手动解释它们。(选择“十六进制”按钮以输入要解释的十六进制值。)
在IEEE-754 32位二进制浮点对象中,如果:
- 位31具有任何值。(它是符号位,与识别NaN无关。)
- 位30到23都是1
- 位22到0并不都是零
(如果第30位到第23位都是1,但第22位到第0位都是0,则该值为无穷大。这不是非法的,但也可能导致低质量的vsnprintf
生成异常。)嗯,应该是这样,但可能他们的观点是“通过逐字节写入来创建浮点溢出条件”,而不仅仅是“创建浮点溢出”。您的错误代码是什么?您是否捕获到浮点异常?您应该了解引发的异常类型,因为FPU可能会导致某些异常(取决于值),尤其是在微控制器环境中,您可能需要自己处理这些异常(取决于您的环境).AVR32不支持浮点异常。得到浮点异常的唯一明显原因是printf()代码失效。这取决于该代码的程序员