Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
691 views
in Technique[技术] by (71.8m points)

assembly - How is floating point conversion actually done in C++?(double to float or float to double)

So I've searched about this topic and found nothing really relevant about it.

I've tried to look at the assembly behind this simple code :

int main(int argc, char *argv[])
{
    double d = 1.0;
    float f = static_cast<float>(d);

    system("PAUSE");
    return 0;
}

which is (with Visual Studio 2012) :

    15:     double d = 1.0;
000000013FD7C16D  movsd       xmm0,mmword ptr [__real@3ff0000000000000 (013FD91AB0h)]  
000000013FD7C175  movsd       mmword ptr [d],xmm0  
    16:     float f = static_cast<float>(d);
000000013FD7C17B  cvtsd2ss    xmm0,mmword ptr [d]  
000000013FD7C181  movss       dword ptr [f],xmm0

I'm not that comfortable with assembly but tried to analyze that anyway. So the first two lines seems to move the double-precision value 3ff0000000000000 into a register, and then move the content of the register to the memory adress of d.

Then, I just don't know exactly what does the next lines. The cvtsd2ss operation is apparently an instruction that convert double precision floating point value to single precision floating point value but I couldn't find what this instruction actually does. (Then the converted value is moved to the memory space of f).

So my question is, how is this conversion actually done by this instruction ? I know that the C++ cast will yield the closest value in the other type but apart from that, I have no idea about the actual operations performed...

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The cvtsd2ss instruction uses the FPU's rounding mode to do the conversion. The default rounding mode is round-to-nearest-even.

In order to follow the algorithm, it helps to keep in mind the information at the IEEE 754-1985 Wikipedia page, especially the diagrams representing the layout.

First, the exponent of the target float is computed: the double type has a wider range than float, so the result may be 0.0f (or a denormal) for a very small double, or an infinite value for a very large double.

For the usual case of a normal double being converted to a normal float (roughly, when the unbiased exponent of the double can be represented in the 8 bits of a single-precision representation), the first 23 bits of the destination significand start out the same as the most significant of the original number's 52-bit significand.

Then there is the problem of rounding:

  • if the left-over bits are below 10..0, then the target significand is left as-is.

  • If the left-over bits are above 10..0, then the target significand is incremented. If incrementing it makes it overflow (because it is already 1..1), then the carry is propagated into the exponent bits. This produces the correct result because of the careful way the IEEE 754 layout has been designed.

  • If the bits left over are exactly 10..0, then the double is exactly midway between two floats. Of these two choices, the one with the last bit 0 (“even”) is chosen.

After this step, the target significand corresponds to the float nearest to the original double.

The directed rounding modes are only simpler. The case where the target float is a denormal is slightly more complicated (one must be careful to avoid “double-rounding”).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...