# performance of random floats

DevFeed: [performance of random floats](<https://devfeed.tech/articles/performance-of-random-floats-36216.md>)

Original publisher: [Read original article](<https://dotat.at/@/2025-06-08-floats.html>)

Published: 2025-06-08T02:08:35Z

Content type: article

Language: en

Sources: [Tony Finch's blog](<https://devfeed.tech/sources/tony-finch-s-blog.md>)

Topics: [floating-point](<https://devfeed.tech/topics/floating-point.md>), [Benchmark](<https://devfeed.tech/topics/benchmark.md>), [Code](<https://devfeed.tech/topics/code.md>), [Arm](<https://devfeed.tech/topics/arm.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>)

Tags: [arm](<https://devfeed.tech/tags/arm.md>), [benchmark](<https://devfeed.tech/tags/benchmark.md>), [code](<https://devfeed.tech/tags/code.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [floating-point](<https://devfeed.tech/tags/floating-point.md>), [performance](<https://devfeed.tech/tags/performance.md>)

## AI overview

This article benchmarks two methods for converting random integers into floating-point values between 0.0 and 1.0: bit manipulation and shift-convert-multiply. It discusses their generated amd64 and Arm64 code, including notably compact Arm64 translations produced by recent Clang versions, and describes tests on Apple M1 Pro and AMD Ryzen 7950X systems.

## Source excerpt

A couple of years ago I wrote about random floating point numbers. In that article I was mainly concerned about how neat the code is, and I didn't pay attention to its performance. Recently, a comment from Oliver Hunt and a blog post from Alisa Sireneva prompted me to wonder if I made an unwarranted assumption. So I wrote a little benchmark, which you can find in pcg-dxsm.git. (Note 2025-06-09: I've edited this post substantially after discovering some problems with the results.) recap code bithack multiply benchmark results conclusion recap Briefly, there are two basic ways to convert a random integer to a floating point number between 0.0 and 1.0: Use bit fiddling to construct an integer whose format matches a float between 1.0 and 2.0; this is the same span as the result but with a simpler exponent. Bitcast the integer to a float and subtract 1.0 to get the result. Shift the integer down to the same range as the mantissa, convert to float, then multiply by a scaling factor that reduces it to the desired range. This produces one more bit of randomness than the bithacking conversion. (There are other less basic ways.) code The double precision code for the two kinds of conversion is below. (Single precision is very similar so I'll leave it out.) It's mostly as I expect, but there are a couple of ARM instructions that surprised me. bithack The bithack function looks like: double bithack52(uint64_t u) { u = ((uint64_t)(1023) << 52) | (u >> 12); return(bitcast(double, u) - 1.0); } It translates fairly directly to amd64 like this: bithack52: shr rdi, 12 movabs rax, 0x3ff0000000000000 or rax, rdi movq xmm0, rax addsd xmm0, qword ptr [rip + .number] ret .number: .quad 0xbff0000000000000 On arm64 the shift-and-or becomes one bfxil instruction (which is a kind of bitfield move), and the constant -1.0 is encoded more briefly. Very neat! bithack52: mov x8, #0x3ff0000000000000 fmov d0, #-1.00000000 bfxil x8, x0, #12, #52 fmov d1, x8 fadd d0, d1, d0 ret multiply The shift-conv