Date: Wed, 6 Dec 2023 03:59:17 +0300
On 12/6/23 01:55, Bongo Ferno via Std-Discussion wrote:
> Should this be a new feature for the c++ language,or is it already
> implemented?
>
> I need to map a 64 bit unsigned integer from {0,1} to 64 bit double {1,-1}
>
> The available solutions are
>
> 1. An if
>
> double mapped = uintFlag ? double(-1.0) : double(1.0);
> // It's slow, because it introduces a branch
Branch isn't slow if it's predictable. In fact, it may be faster than
the non-branch variants that are latency-bound.
> 2. An arithmetic expression
> double mapped = 1 - 2 * int(uintFlag);
> // It's slow, because it needs type conversion
>
> 3. A constant array
> constexpr double mapArray[2] = {1.0, -1.0};
> double answer = mapArray[uintFlag];
> // It's slow, because it needs 10 cycles to fetch from memory, but
> tends to be faster, because it's branchless, and doesn't convert types.
4. Shift flag into the sign bit:
double answer =
bit_cast<double>(bit_cast<uint64_t>(1.0) | (uintFlag << 63u));
This one works well with all compilers.
5. Use conditional move instruction:
double answer =
bit_cast<double>(uintFlag ? bit_cast<uint64_t>(-1.0) :
bit_cast<uint64_t>(1.0));
MSVC messes this one up quite a bit. Gcc also fails to use cmov, but not
as terrible as MSVC.
https://gcc.godbolt.org/z/dW9d9GfMf
> Should this be a new feature for the c++ language,or is it already
> implemented?
>
> I need to map a 64 bit unsigned integer from {0,1} to 64 bit double {1,-1}
>
> The available solutions are
>
> 1. An if
>
> double mapped = uintFlag ? double(-1.0) : double(1.0);
> // It's slow, because it introduces a branch
Branch isn't slow if it's predictable. In fact, it may be faster than
the non-branch variants that are latency-bound.
> 2. An arithmetic expression
> double mapped = 1 - 2 * int(uintFlag);
> // It's slow, because it needs type conversion
>
> 3. A constant array
> constexpr double mapArray[2] = {1.0, -1.0};
> double answer = mapArray[uintFlag];
> // It's slow, because it needs 10 cycles to fetch from memory, but
> tends to be faster, because it's branchless, and doesn't convert types.
4. Shift flag into the sign bit:
double answer =
bit_cast<double>(bit_cast<uint64_t>(1.0) | (uintFlag << 63u));
This one works well with all compilers.
5. Use conditional move instruction:
double answer =
bit_cast<double>(uintFlag ? bit_cast<uint64_t>(-1.0) :
bit_cast<uint64_t>(1.0));
MSVC messes this one up quite a bit. Gcc also fails to use cmov, but not
as terrible as MSVC.
https://gcc.godbolt.org/z/dW9d9GfMf
Received on 2023-12-06 00:59:20