如何检测非 IEEE-754 浮点数,以及如何使用它们?
How to detect non IEEE-754 float, and how to use them?
我正在为基本类型编写 类,因此代码在多个平台和编译器上在逻辑上是相同的(例如 int_least16_t
为 int
)。为了娱乐! (我还是个学生。)
我读了这个:
更糟糕的是:
Floating-point types MAY support special values:
∞, NaN or -0
这意味着 float 可以 是无符号的...
[编辑:是的,这是不同的东西,但没有:“,但必须支持负数”。哟,在标准中没有这样的东西它可能不支持正常的 0 ...(我没有规范。)]
我知道这和 __int128 一样,标准只是标准,
但还是...
IEEE-754 是 1985 年的,但有些机器可能很奇怪,
一些旧硬件没有浮动单元。
据我了解,浮动是强制性的(不像int16_t那样是可选的),
但可以在任何标准中,并且可以是任何一组值?
我们只有一些宏 (<cfloat>
):
FLT_MIN
、FLT_MAX
- 即使 FLT_MIN = IEEE-754::FLT_MIN
,float 也可以是非 IEEE-754。
例如 float with: flipped exponent with fraction...
FLT_RADIX
- 基础系统?如果是这样,可以帮助写出准确的值。但是,float 仍然可以是 3 位或 200 位(大小)...
FLT_EPSILON
-(从 1 到下一个)我们可以用它(带基数)来检查分数大小...
FLT_MANT_DIG
- 是“尾数”数字/分数大小吗?
FLT_MAX_EXP
- 在 IEEE-754 中用 1... 填充的指数,
但是外面可以是随机数?
如果浮点数类似于 IEEE-754(符号、指数、分数),那么很容易,
但如果 -0 和 NaN 是可选的,那么它 可能 不同。
因为我不能区分它们,所以我不能使用位表示
(以安全的方式)。而如果 ∞ 是可选的,那么 float
就不再是安全类型了。
我看到的唯一出路是向编译器添加宏。
我知道这是一个理论上的问题,但我很感兴趣是否可以进行任何检查,或者我们都编写了依赖于实现的代码,当我们使用 float
关键字时?
编辑 2022 年 5 月 4 日:
我想到了这个:
用户例如。代码:
//User eg. code:
int main()
{
float_M a = 1f;
float_M b = 0f;
std::cout << a/b; //should output infinty (IEEE-754)
}
//Code:
class float_M
{
public:
#ifdef __STDC_IEC_559__
float data;
//...
float_M operator/(float_M x){return float_M(data/x.data);}
//...
#else
/*union{
float data;
struct{//For noSign case ("absolutly catastrofic" case)
uint_least8_t sign : 1;
uint_least8_t exponent : 8;
uint_least32_t fraction : 23;
}
}*/ //no noSign case
float data;
//...
float_M operator/(float_M x){return divide(this, x);}
//funtion pointer alert!
static /*const (1*) */ float_M (*divide)(float_M a, float_M b) =
/*std::numeric_limits<float>::is_signed ?(*/
std::numeric_limits<float>::has_infinity ?(
std::numeric_limits<float>::has_quiet_NaN ?(
[]{return float_M(a.data/b.data);}
): &_divide_noNaN
): &_divide_noNaN
/*): &_divide_noSign*/
//...
#endif
}
它很丑(有函数指针),但可以防止在运行时发生错误的跳转。希望c++23有更好的宏
此外,更多链接:
- About Floating-Point Arithmetic
- User-defined literals
- No const funtion pointers (1*)
跟进:
在C++中,std::numeric_limits<T>::is_iec559
shall be true
for all floating-point types T
"if, and only if, the type adheres to ISO/IEC/IEEE 60559"和ISO/IEC/IEEE60559:2011的值与IEEE 754-2008相同,所以:
#include <iostream>
#include <limits>
int main() {
std::cout << std::boolalpha << std::numeric_limits<float>::is_iec559 << '\n';
}
注意:如评论中所述,某些实现可能仍会报告此常量的 true
,即使它们的浮点类型不严格遵循 IEEE 754-2008 标准。
例如,在 gcc
中,您可以使用选项 -Ofast
或 -ffast-math
进行编译,这反过来会设置许多选项,这些选项可能会导致依赖于程序的输出不正确关于数学函数的 IEEE 或 ISO rules/specifications 的精确实现。
在 C99(及更高版本)中,有条件特征宏 __STDC_IEC_559__
和 __STDC_IEC_559_COMPLEX__
,如果在您的实现中可用,将告诉您它是否符合 IEC 60559:1989 / IEEE 754−1985.
#include <stdio.h>
int main(void) {
#ifdef __STDC_IEC_559__
puts("true");
#endif
}
请注意,如果 __STDC_IEC_559__
未定义 ,则不一定意味着该实现不使用 IEEE 754 浮点数。这可能只是意味着它没有这些条件特征宏。关于这些宏的一个有趣的注意事项是,如果您在 gcc
中使用 -Ofast
或 -ffast-math
,它们将不会被定义(与 C++ 测试不同)。
C11 and C17/18 and in C23(草案)中使用的 IEC / IEEE 标准的实际修订版发生了变化,将会有许多与浮点相关的新宏,它(当前)指的是 ISO/IEC60559:2020 和 IEEE 754-2019,其中包含对 IEC 60559:2011 / IEEE 754-2008 的微小升级。
我正在为基本类型编写 类,因此代码在多个平台和编译器上在逻辑上是相同的(例如 int_least16_t
为 int
)。为了娱乐! (我还是个学生。)
我读了这个:
更糟糕的是:
Floating-point types MAY support special values: ∞, NaN or -0
这意味着 float 可以 是无符号的...
[编辑:是的,这是不同的东西,但没有:“,但必须支持负数”。哟,在标准中没有这样的东西它可能不支持正常的 0 ...(我没有规范。)
我知道这和 __int128 一样,标准只是标准, 但还是... IEEE-754 是 1985 年的,但有些机器可能很奇怪, 一些旧硬件没有浮动单元。
据我了解,浮动是强制性的(不像int16_t那样是可选的), 但可以在任何标准中,并且可以是任何一组值?
我们只有一些宏 (<cfloat>
):
FLT_MIN
、FLT_MAX
- 即使FLT_MIN = IEEE-754::FLT_MIN
,float 也可以是非 IEEE-754。 例如 float with: flipped exponent with fraction...FLT_RADIX
- 基础系统?如果是这样,可以帮助写出准确的值。但是,float 仍然可以是 3 位或 200 位(大小)...FLT_EPSILON
-(从 1 到下一个)我们可以用它(带基数)来检查分数大小...FLT_MANT_DIG
- 是“尾数”数字/分数大小吗?FLT_MAX_EXP
- 在 IEEE-754 中用 1... 填充的指数, 但是外面可以是随机数?
如果浮点数类似于 IEEE-754(符号、指数、分数),那么很容易,
但如果 -0 和 NaN 是可选的,那么它 可能 不同。
因为我不能区分它们,所以我不能使用位表示
(以安全的方式)。而如果 ∞ 是可选的,那么 float
就不再是安全类型了。
我看到的唯一出路是向编译器添加宏。
我知道这是一个理论上的问题,但我很感兴趣是否可以进行任何检查,或者我们都编写了依赖于实现的代码,当我们使用 float
关键字时?
编辑 2022 年 5 月 4 日:
我想到了这个:
用户例如。代码:
//User eg. code:
int main()
{
float_M a = 1f;
float_M b = 0f;
std::cout << a/b; //should output infinty (IEEE-754)
}
//Code:
class float_M
{
public:
#ifdef __STDC_IEC_559__
float data;
//...
float_M operator/(float_M x){return float_M(data/x.data);}
//...
#else
/*union{
float data;
struct{//For noSign case ("absolutly catastrofic" case)
uint_least8_t sign : 1;
uint_least8_t exponent : 8;
uint_least32_t fraction : 23;
}
}*/ //no noSign case
float data;
//...
float_M operator/(float_M x){return divide(this, x);}
//funtion pointer alert!
static /*const (1*) */ float_M (*divide)(float_M a, float_M b) =
/*std::numeric_limits<float>::is_signed ?(*/
std::numeric_limits<float>::has_infinity ?(
std::numeric_limits<float>::has_quiet_NaN ?(
[]{return float_M(a.data/b.data);}
): &_divide_noNaN
): &_divide_noNaN
/*): &_divide_noSign*/
//...
#endif
}
它很丑(有函数指针),但可以防止在运行时发生错误的跳转。希望c++23有更好的宏
此外,更多链接:
- About Floating-Point Arithmetic
- User-defined literals
- No const funtion pointers (1*)
跟进:
在C++中,std::numeric_limits<T>::is_iec559
shall be true
for all floating-point types T
"if, and only if, the type adheres to ISO/IEC/IEEE 60559"和ISO/IEC/IEEE60559:2011的值与IEEE 754-2008相同,所以:
#include <iostream>
#include <limits>
int main() {
std::cout << std::boolalpha << std::numeric_limits<float>::is_iec559 << '\n';
}
注意:如评论中所述,某些实现可能仍会报告此常量的 true
,即使它们的浮点类型不严格遵循 IEEE 754-2008 标准。
例如,在 gcc
中,您可以使用选项 -Ofast
或 -ffast-math
进行编译,这反过来会设置许多选项,这些选项可能会导致依赖于程序的输出不正确关于数学函数的 IEEE 或 ISO rules/specifications 的精确实现。
在 C99(及更高版本)中,有条件特征宏 __STDC_IEC_559__
和 __STDC_IEC_559_COMPLEX__
,如果在您的实现中可用,将告诉您它是否符合 IEC 60559:1989 / IEEE 754−1985.
#include <stdio.h>
int main(void) {
#ifdef __STDC_IEC_559__
puts("true");
#endif
}
请注意,如果 __STDC_IEC_559__
未定义 ,则不一定意味着该实现不使用 IEEE 754 浮点数。这可能只是意味着它没有这些条件特征宏。关于这些宏的一个有趣的注意事项是,如果您在 gcc
中使用 -Ofast
或 -ffast-math
,它们将不会被定义(与 C++ 测试不同)。
C11 and C17/18 and in C23(草案)中使用的 IEC / IEEE 标准的实际修订版发生了变化,将会有许多与浮点相关的新宏,它(当前)指的是 ISO/IEC60559:2020 和 IEEE 754-2019,其中包含对 IEC 60559:2011 / IEEE 754-2008 的微小升级。