想改善这个问题吗?更新问题,使其仅通过editing this post专注于一个问题。
3年前关闭。
我是C和一般编程领域的新手。我必须提出某种算法来找到类型的大小,其最大值和最小值。问题是我只能使用代码中提供的那些库(标准stdio.h,math.h和conio.h)。我想到了在C语言中使用溢出的想法。
{
unsigned char c = -1;
for (c; c < 0; c--);
printf("%d\n", c);
unsigned short s = -1;
for (s; s < 0; s--);
printf("%d\n", s);
int i = -1;
while (i < 0) {
i = i - 1024;
}
printf("%d\n", i);
long l = -1;
while (l < 0)
{
l = l - 1024;
}
printf("%d\n", l);
_getch();
return 0;
}
因此,此代码查找无符号类型的最大值。但是我很难找到float,double和long double的值。
最佳答案
您的示例代码有几个问题,但这似乎并不是您真正要问的问题。实际的问题是关于实型的限制:
我很难找到float,double和long double的值。
如果您必须在不依赖标准库的内置功能的情况下(大多数情况下是由float.h
定义的各种宏)来执行此操作,那确实很棘手。实际上,仅凭算术就不能完全做到这一点,因为该标准规定:
如果在表达式的求值过程中发生异常情况(即,如果结果没有在数学上定义或不在其类型的可表示值范围内),则行为不确定。
(C2011,6.5 / 5;添加了重点)
通过算术探究极限的唯一方法是发现结果超出范围的操作,但是您无法便携地识别出这些操作,因为没有任何可靠的方法可以识别未定义的行为(因此将定义行为)。
如果您不能使用float.h
,则仍然可以确定FP极限值,如果
您假定实类型使用带符号的类IEEE-754表示形式,具有未知大小和偏差的二进制指数以及具有未知大小的二进制尾数;
您假设uintmax_t
类型的值位比任何感兴趣的实际类型的尾数位都多;
您假设每种实型的尾数位数不大于相应的最大指数加一;和
您可以依靠数学函数ldexp
(/ ldexpf
/ ldexpl
),该函数定义了当要求计算超出范围的值时的行为。
如果这些条件可以接受,请继续阅读...。
确定FP尾数大小
您可以通过执行从uintmax_t
到到uintmax_t
的往返转换来确定尾数的位数,这些值具有不同数量的有效位(并且没有尾随零)。可以在往返过程中保持不变的最大有效位数是被测FP类型的尾数中的位数。
确定FP指数范围
例如,可以通过将double
与第一个参数调用ldexp()
并为第二个参数使用各种值来确定1.0
的指数范围。不引起范围误差发生的最大指数值是最大基数2指数。不会引起范围误差的最小(最大负值)值大于最小指数减去尾数位数。您可以使用ldexp
系列中适当的特定于类型的函数,对其他实际类型执行相同的操作。
计算极限值
给定实型的尾数大小mbits
和指数限制exp_max
和exp_min
,您可以像这样计算极限值:
最大值:构造一个uintmax_t
值v
,将其mbits
最低位设置为1,并将其所有高位设置为0。将最大值计算为ldexp(v, 1 + exp_max - mbits)
。考虑为什么第二个参数是1 + exp_max - mbits
而不是简单的exp_max
。
最小(正)归一化值:将值计算为ldexp(1, exp_min)
。考虑一下为什么第一个参数是1(或1.0)而不是v
,以及为什么计算不是...
最小(正)子正常值:将值计算为ldexp(1, 1 + exp_min - mbits)
。考虑为什么第二个参数是1 + exp_min - mbits
。如果改用exp_min - mbits
,必然会得到什么值?
一般注意事项
为确保编译器(如果符合)不会使您感到松懈或对转换进行优化,则可能要写入适当实型的volatile
变量,然后再读回值该变量。例如,
uintmax_t probe = < some computation >;
volatile double converted = probe;
_Bool is_equal = (probe == (uintmax_t) converted);
另外,以上过程部分取决于能否识别
ldexp()
报告范围错误。这样做本身有点棘手,但这是另一个问题。关于c - 如何找到float,double,long double的最大值,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40183011/