我是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的值很困难。
答案 0 :(得分:1)
您的示例代码有几个问题,但这似乎不是您实际要问的问题。实际问题是关于真实类型的限制:
我很难找到float,double和long double的值。
如果你必须这样做而不依赖于标准库的内置工具(主要是由float.h
定义的各种宏),那确实很棘手。实际上,由于标准规定了:
如果在评估表达式期间发生异常情况(即,如果结果未在数学上定义 ,则在其类型的可表示值范围内< / em> ),行为未定义。
(C2011,6.5 / 5;重点补充)
通过算术探测极限的唯一方法是发现结果超出范围的操作,但是你无法移植识别那些因为没有任何可靠的方法来识别未定义的行为(因为行为将被定义)。
如果您无法使用float.h
,那么您仍然可以确定限制FP值
uintmax_t
的值位数比任何真实类型的尾数位都多; ldexp
(/ ldexpf
/ ldexpl
),它在被要求计算超出范围的值时定义了行为。如果这些是可接受的条件,请继续阅读......
您可以通过执行从uintmax_t
到&lt; fp type&gt;的往返转换来确定尾数的位数。到uintmax_t
,其值具有不同数量的有效位(并且没有尾随零)。可以在往返行程中保持不变的最大有效位数是被测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()
何时报告范围错误。这本身就有点棘手,但这是另一个问题。