Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does casting and assignment really strip away any extra precision of floats?

I am reading through the new C++ FAQ and I see that even if x == y for double x, y; then it is possible for:

std::cos(x) == std::cos(y)

to evaluate to false. This is because the machine can have a processor which supports extended precision, such that one part of the == is a 64 bit number while the other one is an 80 bit number.

However, the next example seems to be incorrect:

void foo(double x, double y)
{
  double cos_x = cos(x);
  double cos_y = cos(y);
  // the behavior might depend on what's in here
  if (cos_x != cos_y) {
    std::cout << "Huh?!?\n";  // You might end up here when x == y!!
  }
}

As far as I read on en.cppreference.com here:

Cast and assignment strip away any extraneous range and precision: this models the action of storing a value from an extended-precision FPU register into a standard-sized memory location.

Hence, assigning:

double cos_x = cos(x);
double cos_y = cos(y);

should trim away any extra precision and make the program perfectly predictable.

So, who is right? The C++ FAQ, or the en.cppreference.com?

like image 979
Martin Drozdik Avatar asked May 05 '16 20:05

Martin Drozdik


People also ask

What is the difference between twin roll casting and DC casting?

A key difference between twin roll casting and DC casting is the solidification rate. While in DC casting it is limited to 1–50 °C/s, it reaches 500–1000 °C/s in a twin roll caster, leading to greatly refined structures with small and finely distributed intermetallic phases, extended solid solutions and fine grain sizes.

What are direct strip cast alloys?

Direct Strip Cast Alloys There have been substantial developments in the mass production of iron alloys by direct strip casting (DSC) which produces as-cast strip products of a thickness less than 2 mm. Iron alloys currently produced by DSC include carbon and alloy steels, stainless steel, iron–silicon alloys, and cast iron.

What is the casting rate of thin slab casting?

The basic idea of thin slab casting is to cast typically 40 to 80 mm thick slab. The casting rate should be relatively high 4–20 m/min in order to attain the same production rate as with the conventional caster. With conventional slab caster, the withdrawal rate varies from about 1.0 to 1.8 m/min.

Can casting scrap be used as filler wire?

A strip casting scrap can also be used as a filler wire. The casting filler wire can be used for casting welding and salvaging casting. But the casting scrap and casting wire must be selected carefully to ensure that there are no slag inclusion and rarefaction defects in them.


2 Answers

Neither the ISOCPP FAQ or cppreference are authoritative sources. cppreference is essentially the equivalent of wikipedia: it contains good information, but anybody can add anything without sources you have to read it with a grain of salt. Are the following three statements true:

Did you catch that? Your particular installation might store the result of one of the cos() calls out into RAM, truncating it in the process, then later compare that truncated value with the untruncated result of the second cos() call. Depending on lots of details, those two values might not be equal.

This is because the machine can have a processor which supports extended precision, such that one part of the == is a 64 bit number while the other one is an 80 bit number.

Cast and assignment strip away any extraneous range and precision: this models the action of storing a value from an extended-precision FPU register into a standard-sized memory location.

Maybe. It depends on the platform, your compiler, the compiler options, or any number of things. Realistically, the above statements only hold true for GCC in 32-bit mode, which defaults to the legacy x87 FPU (where everything is 80-bits internally) and rounded down to 64-bit when storing in memory. 64-bit uses SSE so double temporaries are always 64-bit. You can force SSE with mfpmath=sse and -msse2. Either way, the assembly might look something like this:

    movsd   QWORD PTR [rsp+8], xmm1
    call    cos
    movsd   xmm1, QWORD PTR [rsp+8]
    movsd   QWORD PTR [rsp], xmm0
    movapd  xmm0, xmm1
    call    cos
    movsd   xmm2, QWORD PTR [rsp]
    ucomisd xmm2, xmm0

As you can see there is no truncation of any sort nor 80-bit registers used here.

like image 188
uh oh somebody needs a pupper Avatar answered Oct 21 '22 06:10

uh oh somebody needs a pupper


I wish that assignment or casting would toss away the extra precision. I have worked with "clever" compilers for which this does not happen. Many do, but if you want truly machine-independent code, you need do extra work.

You can force the compiler to always use the value in memory with the expected precision by declaring the variable with the "volatile" keyword.

Some compilers pass parameters in registers rather than on the stack. For these compilers, it could be that x or y could have unintended extra precision. To be totally safe, you could do

volatile double  db_x = x,          db_y = y;
volatile double cos_x = cos(db_x), cos_y = cos(db_y);
if (cos_x != cos_y)...
like image 37
Reality Pixels Avatar answered Oct 21 '22 07:10

Reality Pixels