C 中是否使用了 IEEE-754 表示法?
Is IEEE-754 representation used in C?
我必须使用 IEEE-754 对电子电荷进行编码,即 -1.602*10-19 C。我手动完成并使用 this 网站验证了我的结果。所以我知道我的代表很好。我的问题是,如果我尝试构建一个以科学记数法显示我的数字的 C 程序,我会得到错误的数字。
这是我的代码:
#include <stdio.h>
int main(int argc, char const *argv[])
{
float q = 0xa03d217b;
printf("q = %e", q);
return 0;
}
结果如下:
$ ./test.exe
q = 2.688361e+09
我的问题:除 IEEE-754 之外,我的 CPU 是否可能在内部用于浮点的另一种表示形式?
行 float q = 0xa03d217b;
将 整数(十六进制)文字 转换为表示该数字(或其近似值)的 float
值;因此,分配给您的 q
的值将是(十进制)值 2,688,360,827
(这就是 0xa03d217b
等同于),正如您所指出的。
如果您必须使用其内部 IEEE-754 (HEX) 表示初始化一个 float
变量,那么您最好的选择是使用 type punning 通过 union
的成员(在 C 中是合法的,但在 C++ 中 不是 ):
#include <stdio.h>
typedef union {
float f;
unsigned int h;
} hexfloat;
int main()
{
hexfloat hf;
hf.h = 0xa03d217b;
float q = hf.f;
printf("%lg\n", q);
return 0;
}
还有一些 'quick tricks' 使用指针转换,例如:
unsigned iee = 0xa03d217b;
float q = *(float*)(&iee);
但是,请注意,此类方法存在许多问题,例如 potential endianness conflicts and the fact that you're breaking strict aliasing requirements。
因此,q
不包含您期望的值。十六进制值被转换为具有相同值(具有近似值)的浮点数,而不是具有相同的位表示。
使用g++和选项-Wall编译时,出现警告:
warning: implicit conversion from 'unsigned int' to 'float' changes value from 2688360827 to 2688360704 [-Wimplicit-const-int-float-conversion]
可以测试on Compiler Explorer.
gcc 显然不支持此警告。相反,您可以使用选项 -Wfloat-conversion(不是 -Wall -Wextra 的一部分):
warning: conversion from 'unsigned int' to 'float' changes value from '2688360827' to '2.6883607e+9f' [-Wfloat-conversion]
My problem is that if I try to build a c program showing my the number in scientific notation.
如果您的目标机器可能会或可能不会使用 IEEE754 编码怎么办?复制位模式可能会失败。
如果从 binary32 常量 0xa03d217b 开始,代码可以对其进行检查,然后构建可用于该实现的最佳 float
。
#include <math.h>
#define BINARY32_MASK_SIGN 0x80000000
#define BINARY32_MASK_EXPO 0x7FE00000
#define BINARY32_MASK_SNCD 0x007FFFFF
#define BINARY32_IMPLIED_BIT 0x800000
#define BINARY32_SHIFT_EXPO 23
float binary32_to_float(uint32_t x) {
// Break up into 3 parts
bool sign = x & BINARY32_MASK_SIGN;
int biased_expo = (x & BINARY32_MASK_EXPO) >> BINARY32_SHIFT_EXPO;
int32_t significand = x & BINARY32_MASK_SNCD;
float y;
if (biased_expo == 0xFF) {
y = significand ? NAN : INFINITY; // For simplicity, NaN payload not copied
} else {
int expo;
if (biased_expo > 0) {
significand |= BINARY32_IMPLIED_BIT;
expo = biased_expo - 127;
} else {
expo = 126;
}
y = ldexpf((float)significand, expo - BINARY32_SHIFT_EXPO);
}
if (sign) {
y = -y;
}
return y;
}
示例用法和输出
#include <float.h>
#include <stdio.h>
int main() {
float e = -1.602e-19;
printf("%.*e\n", FLT_DECIMAL_DIG, e);
uint32_t e_as_binary32 = 0xa03d217b;
printf("%.*e\n", FLT_DECIMAL_DIG, binary32_to_float(e_as_binary32));
}
-1.602000046e-19
-1.602000046e-19
请注意,C 支持十六进制浮点数作为文字。有关详细信息,请参阅 https://en.cppreference.com/w/cpp/language/floating_literal。这种表示法对于以可移植的方式编写数字很有用,而无需担心四舍五入问题,如果您以常规 decimal/scientific 表示法编写它就会出现这种情况。这是您感兴趣的号码:
#include <stdio.h>
int main(void) {
float f = -0x1.7a42f6p-63;
printf("%e\n", f);
return 0;
};
当我运行这个程序时,我得到:
$ make a
cc a.c -o a
$ ./a
-1.602000e-19
只要您的编译器支持这种表示法,您就不必担心底层机器如何表示浮点数,只要这个特定数字符合其 float
表示法即可。
我必须使用 IEEE-754 对电子电荷进行编码,即 -1.602*10-19 C。我手动完成并使用 this 网站验证了我的结果。所以我知道我的代表很好。我的问题是,如果我尝试构建一个以科学记数法显示我的数字的 C 程序,我会得到错误的数字。
这是我的代码:
#include <stdio.h>
int main(int argc, char const *argv[])
{
float q = 0xa03d217b;
printf("q = %e", q);
return 0;
}
结果如下:
$ ./test.exe
q = 2.688361e+09
我的问题:除 IEEE-754 之外,我的 CPU 是否可能在内部用于浮点的另一种表示形式?
行 float q = 0xa03d217b;
将 整数(十六进制)文字 转换为表示该数字(或其近似值)的 float
值;因此,分配给您的 q
的值将是(十进制)值 2,688,360,827
(这就是 0xa03d217b
等同于),正如您所指出的。
如果您必须使用其内部 IEEE-754 (HEX) 表示初始化一个 float
变量,那么您最好的选择是使用 type punning 通过 union
的成员(在 C 中是合法的,但在 C++ 中 不是 ):
#include <stdio.h>
typedef union {
float f;
unsigned int h;
} hexfloat;
int main()
{
hexfloat hf;
hf.h = 0xa03d217b;
float q = hf.f;
printf("%lg\n", q);
return 0;
}
还有一些 'quick tricks' 使用指针转换,例如:
unsigned iee = 0xa03d217b;
float q = *(float*)(&iee);
但是,请注意,此类方法存在许多问题,例如 potential endianness conflicts and the fact that you're breaking strict aliasing requirements。
因此,q
不包含您期望的值。十六进制值被转换为具有相同值(具有近似值)的浮点数,而不是具有相同的位表示。
使用g++和选项-Wall编译时,出现警告:
warning: implicit conversion from 'unsigned int' to 'float' changes value from 2688360827 to 2688360704 [-Wimplicit-const-int-float-conversion]
可以测试on Compiler Explorer.
gcc 显然不支持此警告。相反,您可以使用选项 -Wfloat-conversion(不是 -Wall -Wextra 的一部分):
warning: conversion from 'unsigned int' to 'float' changes value from '2688360827' to '2.6883607e+9f' [-Wfloat-conversion]
My problem is that if I try to build a c program showing my the number in scientific notation.
如果您的目标机器可能会或可能不会使用 IEEE754 编码怎么办?复制位模式可能会失败。
如果从 binary32 常量 0xa03d217b 开始,代码可以对其进行检查,然后构建可用于该实现的最佳 float
。
#include <math.h>
#define BINARY32_MASK_SIGN 0x80000000
#define BINARY32_MASK_EXPO 0x7FE00000
#define BINARY32_MASK_SNCD 0x007FFFFF
#define BINARY32_IMPLIED_BIT 0x800000
#define BINARY32_SHIFT_EXPO 23
float binary32_to_float(uint32_t x) {
// Break up into 3 parts
bool sign = x & BINARY32_MASK_SIGN;
int biased_expo = (x & BINARY32_MASK_EXPO) >> BINARY32_SHIFT_EXPO;
int32_t significand = x & BINARY32_MASK_SNCD;
float y;
if (biased_expo == 0xFF) {
y = significand ? NAN : INFINITY; // For simplicity, NaN payload not copied
} else {
int expo;
if (biased_expo > 0) {
significand |= BINARY32_IMPLIED_BIT;
expo = biased_expo - 127;
} else {
expo = 126;
}
y = ldexpf((float)significand, expo - BINARY32_SHIFT_EXPO);
}
if (sign) {
y = -y;
}
return y;
}
示例用法和输出
#include <float.h>
#include <stdio.h>
int main() {
float e = -1.602e-19;
printf("%.*e\n", FLT_DECIMAL_DIG, e);
uint32_t e_as_binary32 = 0xa03d217b;
printf("%.*e\n", FLT_DECIMAL_DIG, binary32_to_float(e_as_binary32));
}
-1.602000046e-19
-1.602000046e-19
请注意,C 支持十六进制浮点数作为文字。有关详细信息,请参阅 https://en.cppreference.com/w/cpp/language/floating_literal。这种表示法对于以可移植的方式编写数字很有用,而无需担心四舍五入问题,如果您以常规 decimal/scientific 表示法编写它就会出现这种情况。这是您感兴趣的号码:
#include <stdio.h>
int main(void) {
float f = -0x1.7a42f6p-63;
printf("%e\n", f);
return 0;
};
当我运行这个程序时,我得到:
$ make a
cc a.c -o a
$ ./a
-1.602000e-19
只要您的编译器支持这种表示法,您就不必担心底层机器如何表示浮点数,只要这个特定数字符合其 float
表示法即可。