提问人:CaptainParsifal 提问时间:10/9/2023 最后编辑:Adrian MoleCaptainParsifal 更新时间:10/11/2023 访问量:142
试图找到浮点数、双精度数、长双精度数的最小正数。适用于 double 和 long double,但不适用于浮点
Trying to find smallest positive number for float, double, long double. Works for double and long double but fails for float
问:
我正在尝试为每种数据类型(浮点数、双精度数和长双精度数)找到最大和最小数字。我正在使用一个循环,我将每个值与无穷大(最大数字)和 0(最小数字)进行比较。然后,它打印找到的值。它为我提供了双精度和长双精度的正确值,浮点型中的最大数字也是正确的。while
但是,对于最小的浮点数,它打印 0。当我修改程序以显示循环中的每个值时,正确的值是倒数第二个,但之后,由于某种原因,循环再次进行,说 0 > 0 并将 0 打印为最小值。
我不明白,为什么会这样?即使最后一个值太小以至于四舍五入为 0,为什么它会决定 0 > 0 并让循环最后一次进行?
这是程序:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
float big_f = 1, small_f = 1;
double big_d = 1, small_d = 1;
long double big_ld = 1, small_ld = 1;
while(!(isinf(big_f*2)))
{
big_f *= 2;
}
while((small_f*0.5)>0 and !((small_f*0.5)==0))
{
small_f *= 0.5;
}
cout << "Najmensie cislo float je "<< small_f << endl;
cout << "Najvacsie cislo float je "<< big_f << endl;
while(!(isinf(big_d*2)))
{
big_d *= 2;
}
while((small_d*0.5)>0)
{
small_d *= 0.5;
}
cout << "Najmensie cislo double je "<< small_d << endl;
cout << "Najvacsie cislo double je "<< big_d << endl;
while(!(isinf(big_ld*2)))
{
big_ld *= 2;
}
while((small_ld*0.5)>0)
{
small_ld *= 0.5;
}
cout << "Najmensie cislo long double je "<< small_ld << endl;
cout << "Najvacsie cislo long double je "<< big_ld << endl;
}
请注意,这是针对学校的,我不能只将其与.FLT_MIN
答:
0.5
是一个常数,因此转换为算术并用于算术。然后测试是否尚未达到 a 达到零的点。double
small_f*0.5
small_f
double
double
(small_f*0.5)>0
small_f
double
要解决此问题,请使用 .或者,使用 并让 转换为 .0.5
0.5f
float
small_f/2
int
2
float
此外,C++ 标准允许实现在计算表达式时使用比名义类型更高的精度,因此,例如,即使 和 是,也可以用算术计算,或者可以用 即使 和 是 来计算。为了防止这种情况,请将值分配给对象或执行强制转换,这是“放弃”过高精度所必需的:。x*y
double
long double
x
y
float
long double
x
y
double
(float) (small_f/2) > 0
评论
-fexcess-precision=standard
-std=c++XX
-std=gnu++XX
-ffp-contract=off
0
这并不能直接回答你的问题,但是如果我试图了解浮点数,我会看看它们是如何表示的:特别是IEEE格式--参见 https://en.wikipedia.org/wiki/IEEE_754,看看我是否可以通过受规范启发的编码来获得答案。浮点数本质上是符号 * 分数 * 指数,在进行数值工作时,理解这一点确实非常有帮助。
例如,为了获得最高的浮点数,我写了这个。FLT_MAX
float largest_floating_point()
{
const unsigned mantissa_index = 0;
const unsigned exponent_index = 23;
const unsigned sign_index = 31;
// maximise mantissa
// E.g. here we subtract 1 from binary 1,00000000 to get binary 0,11111111
const unsigned mantissa = (1 << (exponent_index - mantissa_index)) - 1;
// maximise exponent
const unsigned num_nan_bits = 1;
const unsigned exponent = (1 << (sign_index - exponent_index)) - 1 - num_nan_bits;
// sign is zero for largest number
const unsigned sign = 0;
// combine by shifting and ORing bits together
const unsigned bit_pattern =
(mantissa << mantissa_index) | (exponent << exponent_index) | (sign << sign_index);
// cast to float -- go via array of bytes to avoid arithmetic conversion
static_assert(sizeof(unsigned) == sizeof(float));
union
{
unsigned u;
float f;
} n;
n.u = bit_pattern;
return n.f;
}
这不符合你使用循环的方法,也不是人们想要在生产中使用的程序,尤其是因为严格来说,铸造是未定义的。但这适用于 Visual C++ (Windows) 和 gcc (linux)。
我从中学到了很多东西,也从编写代码(未显示)中学到了很多东西。我已经编程了很长时间,并认为我非常了解浮点表示。事实证明我没有,:)学到了一些东西。FLT_MIN
如果您选择探索这种方法以获得限制,请仔细注意规范,特别是主要文章中的“偏差”,NaN 的表示方式 (https://en.wikipedia.org/wiki/NaN) 和零的表示方式 (https://en.wikipedia.org/wiki/Signed_zero)。
评论
-fno-strict-aliasing
'array' is used uninitialized
array
((unsigned*)array)[0] = bit_pattern;
unsigned
float
union { uint32_t u; float f; } n; n.u = 1; printf("%Le\n", (long double)n.f);
评论
float
double
float
double
double
float
(small_f*0.5)>0
(static_cast<double>(small_f) * 0.5) > 0
std::numeric_limits
while
for