Converting binary floating-point numbers to integers
lemire.me
lemire.me
for (double x = 1; x < 1000000000; x += 0.5) {
counter++;
int64_t tmp;
if (to_int64_simple(x, &tmp)) {
sum += tmp;
}
}The fractional part is always mostly 0.5, or 0.10000... While that shouldn't really affect things, I think a proper test would sample randomly, though this runs into the problem of the random number generator itself influencing the time spent, so I can see the appeal for this method. Perhaps generating a random float array with N elements and calculating the results for x + arr[x%N] would accomplish this.
[1]: https://randomascii.wordpress.com/2014/01/27/theres-only-fou...
Similarly you definitely should have a table of known numbers you want to test and not just go through the space by 0.5. You want to test denormals, stuff like 1/3, etc.
The results aren't too surprising. The ARM, which is a RISC, doesn't show much difference because it doesn't have much in the way of good complex instructions suited to the task, and in this case you can actually beat the compiler by optimising at the source level. x86 is still fundamentally CISC in nature and making use of the complex instructions is better especially when they are optimised in hardware. I don't have those machines nor environment to compare, but if you look at the code size, you might find the compiler has generated very similar code for the long and short version on ARM, whereas it certainly won't be smart enough to "recompress" your long version back into CISC instructions.
(Edit: and as one of the blog post comments notes, for the special case of double to 32 bit integer the FCVTJS insn does this and puts the 'exact or not' information conveniently in the Z flag to branch on.)
typedef union {
struct {
uint64_t fraction : 52;
uint32_t exp_bias : 11;
uint32_t sign : 1;
} fields;
double value;
} binary64_float;
Accessing the value stored in "value" through the "fields" member is undefined behavior. I'm legitimately surprised that lemire published this code. The correct and well-defined way to do this is to memcpy() the double value to a char array and access the relevant bits that way.I’m surprised at that. Can you quote the relevant part of the spec that you think makes this undefined behaviour?