Sample code (t50.c):
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <math.h>
#include <float.h>
#include <assert.h>
const float d1 = NAN;
const float d2 = -0x0p+0;
const float d3 = NAN / -0x0p+0;
typedef union { uint32_t u; float d; } u_t;
int main(void)
{
u_t u1;
u_t u2;
u_t u3;
u1.d = *(volatile float*)&d1 / *(volatile float*)&d2;
u2.d = d3;
u3.d = d1 / d2;
if ( u1.u != u2.u || u1.u != u3.u )
{
printf("error:\n");
printf("u1 (run time) %08"PRIx32" %.*e\n", u1.u, DECIMAL_DIG, u1.d);
printf("u2 (compile time) %08"PRIx32" %.*e\n", u2.u, DECIMAL_DIG, u2.d);
printf("u3 %08"PRIx32" %.*e\n", u3.u, DECIMAL_DIG, u3.d);
}
return 0;
}
Compiler invocation: cl t50.c /O1 /fp:precise && t50
Expected result: <nothing>
Actual result (same for cl x86 and cl x64):
error:
u1 (run time) ffc00000 -nan(ind)
u2 (compile time) 7f800000 inf
u3 ffc00000 -nan(ind)
I've specified /fp:strict: cl t50.c /O1 /fp:strict && t50, but got:
t50.c(8): error C2099: initializer is not a constant
t50.c(10): error C2099: initializer is not a constant
cl version: 19.25.28611 for x86 and 19.25.28611 for x64.
Compare with gcc (10.2.0) and clang (11.0.0):
gcc t50.c -O2 && a.exe
<nothing>
clang t50.c -O2 && a.exe
<nothing>
Why? What I'm missing here?
What the standard (C / IEEE) says?
UPD1:
Same result for if ( u1.d != u2.d || u1.d != u3.d ).
Same result w/o unions (i.e. using float u1, u2, u3).
UPD2:
compiler's NAN definition: Windows Kits\10\Include\10.0.18362.0\ucrt\corecrt_math.h: #define NAN ((float)(INFINITY * 0.0F)).
Output for u1.d = NAN; printf("NAN %08"PRIx32" %.*e\n", u1.u, DECIMAL_DIG, u1.d); (for both cl x86 and cl x64): NAN ffc00000 -nan(ind).
Why?
cl does not follow IEEE-754 concerning NAN.
What I'm missing here?
Assuming a compliant C compiler follows IEEE.
What the standard C says?
C is lax with specs in the NAN department. I'd rate the compiler as compliant, just a weak quality of implementation concerning NAN.
What the standard IEEE says?
Non-compliant.
Related
Compiling and running this code:
// List the range of the long double.
#include <stdio.h>
#include <float.h>
int main() {
printf("Long double: %Lg - %Lg\n", LDBL_MIN, LDBL_MAX);
}
Gives this result:
Long double: 3.3621e-4932 - 1.18973e+4932
Yet this code:
#include <stdio.h>
#include <float.h>
int main() {
long double ld = 1.18973e+4932;
printf("Longest double: %Lg", ld);
}
Gives this warning when compiled:
gcc -std=gnu99 -o fj -Wall -Wno-format-overflow -g r2.c -lm
r2.c:4:3: warning: floating constant exceeds range of ‘double’ [-Woverflow]
4 | long double ld = 1.18973e+4932;
| ^~~~
However, if you compile:
#include <stdio.h>
#include <float.h>
int main() {
long double ld = LDBL_MAX;
printf("Longest double: %Lg\n", ld);
}
It compiles and runs:
Longest double: 1.18973e+4932
What's going on here? It should accept the numerical limit that was listed in the first program, but it does just fine with the LDBL_MAX version of it.
My compiler:
gcc --version
gcc (Debian 10.2.1-6) 10.2.1 20210110
My computer:
AMD Ryzen 5 5600G with Radeon Graphics
CPU MHz: 3057.560
BogoMIPS: 7785.19
CPU cache size: 512 KB
Debian GNU/Linux 11 (bullseye)
1.18973e+4932 is an out-of-range double constant.
LDBL_MAX is an in range long double constant.
Make the floating point constant a long double by appending an L.
Lower case l is an option too, yet harder to distinguish from 1.
// long double ld = 1.18973e+4932;
long double ld = 1.18973e+4932L; // Yet this is not quite the max
// max value better with adequate precision as
long double ld = 1.18973149535723176502e+4932L;
// Should print the same.
printf("Longest double: %.*Lg\n", LDBL_DECIMAL_DIG, ld);
printf("Longest double: %.*Lg\n", LDBL_DECIMAL_DIG, LDBL_MAX);
When coding near the limits, consider hex notation for better control in rounding issues.
long double ld = 1.1897315e+4932L; --> Infinity
long double ld = 1.18973149535723177e+4932L; --> Infinity
long double ld = 1.18973149535723176506e+4932L; --> Infinity
// 1.18973149535723176502e+4932L
long double ld = 0x1.fffffffffffffffep+16383L;
Code (t125.c):
#include <fenv.h>
#include <stdint.h>
#include <stdio.h>
#if _MSC_VER
#pragma fenv_access (on)
#else
#pragma STDC FENV_ACCESS ON
#endif
void show_fe_exceptions(void)
{
printf("exceptions raised: ");
if (fetestexcept(FE_DIVBYZERO)) printf(" FE_DIVBYZERO");
if (fetestexcept(FE_INEXACT)) printf(" FE_INEXACT");
if (fetestexcept(FE_INVALID)) printf(" FE_INVALID");
if (fetestexcept(FE_OVERFLOW)) printf(" FE_OVERFLOW");
if (fetestexcept(FE_UNDERFLOW)) printf(" FE_UNDERFLOW");
if (fetestexcept(FE_ALL_EXCEPT)==0) printf(" none");
printf("\n");
}
typedef union { uint32_t u; float f; } ufloat;
int main(void)
{
_Bool b;
ufloat uqnan;
volatile float f;
uqnan.u = 0x7fc00000;
f = uqnan.f;
b = f == f;
show_fe_exceptions();
return b ? 1 : 0;
}
Invocations:
$ gcc t125.c -Wall -Wextra -pedantic -std=c17 && ./a.exe
t125.c:7: warning: ignoring ‘#pragma STDC FENV_ACCESS’ [-Wunknown-pragmas]
7 | #pragma STDC FENV_ACCESS ON
|
exceptions raised: none
$ clang t125.c -Wall -Wextra -pedantic -std=c17 && ./a.exe
t125.c:7:14: warning: pragma STDC FENV_ACCESS ON is not supported, ignoring pragma [-Wunknown-pragmas]
#pragma STDC FENV_ACCESS ON
^
1 warning generated.
exceptions raised: none
$ cl t125.c /fp:strict /std:c17 && t125
exceptions raised: none
Question: why QNAN == QNAN does not lead to raising FE_INVALID exception?
UPD. Reason of the question: (false, see below) assumption that <any_NAN> == <any_NAN> leads to raising FE_INVALID exception.
UPD2. Changed code: from f = *(float*)&qnan to f = uqnan.f (type punning via union). This is to avoid violation of the aliasing rules of the C standard.
ISO/IEC 9899:2011 (E) (emphasis added):
5.2.4.2.2 Characteristics of floating types <float.h>
3 A quiet NaN propagates through almost every arithmetic operation without raising a floating-point exception; a signaling NaN generally raises a floating-point exception when occurring as an arithmetic operand.
See also: What is the difference between quiet NaN and signaling NaN?.
UPD. Yes, it seems that equality does not count as an arithmetic operation for this purpose. Then here is a quote from IEEE 754-2008 (emphasis added):
5.11 Details of comparison predicates
Programs that explicitly take account of the possibility of quiet NaN operands may use the unordered-quiet predicates in Table 5.3 which do not signal such an invalid operation exception.
For example, the predicate LT EQ shall not lead to raising invalid operation exception. However, we see (in the comments above) that for f <= f both gcc and cl (msvc) raise FE_INVALID. Is it a bug / defect? Though none of them define __STDC_IEC_559__ with definition of 1. However, they are not required:
__STDC_IEC_559__ The integer constant 1, intended to indicate conformance to the specifications in annex F (IEC 60559 floating-point arithmetic).
I ran into an interesting issue when compiling some code with -O3 using clang on OSX High Sierra. The code is this:
#include <stdint.h>
#include <limits.h> /* for CHAR_BIT */
#include <stdio.h> /* for printf() */
#include <stddef.h> /* for size_t */
uint64_t get_morton_code(uint16_t x, uint16_t y, uint16_t z)
{
/* Returns the number formed by interleaving the bits in x, y, and z, also
* known as the morton code.
*
* See https://graphics.stanford.edu/~seander/bithacks.html#InterleaveTableO
bvious.
*/
size_t i;
uint64_t a = 0;
for (i = 0; i < sizeof(x)*CHAR_BIT; i++) {
a |= (x & 1U << i) << (2*i) | (y & 1U << i) << (2*i + 1) | (z & 1U << i)
<< (2*i + 2);
}
return a;
}
int main(int argc, char **argv)
{
printf("get_morton_code(99,159,46) = %llu\n", get_morton_code(99,159,46));
return 0;
}
When compiling this with cc -O1 -o test_morton_code test_morton_code.c I get the following output:
get_morton_code(99,159,46) = 4631995
which is correct. However, when compiling with cc -O3 -o test_morton_code test_morton_code.c:
get_morton_code(99,159,46) = 4294967295
which is wrong.
What is also odd is that this bug appears in my code when switching from -O2 to -O3 whereas in the minimal working example above it appears when going from -O1 to -O2.
Is this a bug in the compiler optimization or am I doing something stupid that's only appearing when the compiler is optimizing more aggressively?
I'm using the following version of clang:
snotdaqs-iMac:snoFitter snoperator$ cc --version
Apple LLVM version 9.1.0 (clang-902.0.39.1)
Target: x86_64-apple-darwin17.5.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
UndefinedBehaviorSanitizer is really helpful in catching such mistakes:
$ clang -fsanitize=undefined -O3 o3.c
$ ./a.out
o3.c:19:2: runtime error: shift exponent 32 is too large for 32-bit type 'unsigned int'
get_morton_code(99,159,46) = 4294967295
A possible fix would be replacing the 1Us with 1ULL, an unsigned long long is at least 64 bit and can be shifted that far.
When i is 15 in the loop, 2*i+2 is 32, and you are shifting an unsigned int by the number of bits in an unsigned int, which is undefined.
You apparently intend to work in a 64-bit field, so cast the left side of the shift to uint64_t.
A proper printf format for uint64_t is get_morton_code(99,159,46) = %" PRIu64 "\n". PRIu64 is defined in the <inttypes.h> header.
I have the following C program:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
int main() {
const int opt_count = 2;
int oc = 30;
int c = 900;
printf("%d %f\n", c, pow(oc, opt_count));
assert(c == (int)(pow(oc, opt_count)));
}
I'm running MinGW on Windows 8.1. Gcc version 4.9.3. I compile my program with:
gcc program.c -o program.exe
When I run it I get this output:
$ program
900 900.000000
Assertion failed: c == (int)(pow(oc, opt_count)), file program.c, line 16
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
What is going on? I expect the assertion to pass because 900 == 30^2.
Thanks!
Edit
I'm not using any fractions or decimals. I'm only using integers.
This happens when the implementation of pow is via
pow(x,y) = exp(log(x)*y)
Other library implementations first reduce the exponent by integer powers, thus avoiding this small floating point error.
More involved implementations contain steps like
pow(x,y) {
if(y<0) return 1/pow(x, -y);
n = (int)round(y);
y = y-n;
px = x; powxn = 1;
while(n>0) {
if(n%2==1) powxn *= px;
n /=2; px *= px;
}
return powxn * exp(log(x)*y);
}
with the usual divide-n-conquer resp. halving-n-squaring approach for the integer power powxn.
You have a nice answer (and solution) from #LutzL, another solution is comparing the difference with an epsilon, e.g.: 0.00001, in this way you can use the standard function pow included in math.h
#define EPSILON 0.0001
#define EQ(a, b) (fabs(a - b) < EPSILON)
assert(EQ((double)c, pow(oc, opt_count)));
The following program (adapted from here) is giving inconsistent results when compiled with GCC (4.8.2) and Clang (3.5.1). In particular, the GCC result does not change even when FLT_EVAL_METHOD does.
#include <stdio.h>
#include <float.h>
int r1;
double ten = 10.0;
int main(int c, char **v) {
printf("FLT_EVAL_METHOD = %d\n", FLT_EVAL_METHOD);
r1 = 0.1 == (1.0 / ten);
printf("0.1 = %a, 1.0/ten = %a\n", 0.1, 1.0 / ten);
printf("r1=%d\n", r1);
}
Tests:
$ gcc -std=c99 t.c && ./a.out
FLT_EVAL_METHOD = 0
0.1 = 0x1.999999999999ap-4, 1.0/ten = 0x1.999999999999ap-4
r1=1
$ gcc -std=c99 -mpfmath=387 t.c && ./a.out
FLT_EVAL_METHOD = 2
0.1 = 0x0.0000000000001p-1022, 1.0/ten = 0x0p+0
r1=1
$ clang -std=c99 t.c && ./a.out
FLT_EVAL_METHOD = 0
0.1 = 0x1.999999999999ap-4, 1.0/ten = 0x1.999999999999ap-4
r1=1
$ clang -std=c99 -mfpmath=387 -mno-sse t.c && ./a.out
FLT_EVAL_METHOD = 2
0.1 = 0x0.07fff00000001p-1022, 1.0/ten = 0x0p+0
r1=0
Note that, according to this blog post, GCC 4.4.3 used to output 0 instead of 1 in the second test.
A possibly related question indicates that a bug has been corrected in GCC 4.6, which might explain why GCC's result is different.
I would like to confirm if any of these results would be incorrect, or if some subtle evaluation steps (e.g. a new preprocessor optimization) would justify the difference between these compilers.
This answer is about something that you should resolve before you go further, because it is going to make reasoning about what happens much harder otherwise:
Surely printing 0.1 = 0x0.07fff00000001p-1022 or 0.1 = 0x0.0000000000001p-1022 can only be a bug on your compilation platform caused by ABI mismatch when using -mfpmath=387. None of these values can be excused by excess precision.
You could try to include your own conversion-to-readable-format in the test file, so that that conversion is also compiled with -mfpmath=387. Or make a small stub in another file, not compiled with that option, with a minimalistic call convention:
In other file:
double d;
void print_double(void)
{
printf("%a", d);
}
In the file compiled with -mfpmath=387:
extern double d;
d = 0.1;
print_double();
Ignoring the printf problem which Pascal Cuoq addressed, I think GCC is correct here: according to the C99 standard, FLT_EVAL_METHOD == 2 should
evaluate all operations and constants to the range and precision of the long double type.
So, in this case, both 0.1 and 1.0 / ten are being evaluated to an extended precision approximation of 1/10.
I'm not sure what Clang is doing, though this question might provide some help.