---
title: "Convert fixed-point to double in C#"
url: https://recursiveai.org/onemath/cookbook/fixed-point-bridge/
description: "Convert Q31.32 fixed-point values to and from double and float in C#, exactly where possible, with one documented rounding and a clear error out of range. Runnable code, with OneMath."
version: "1.0.0"
---

# Convert fixed-point to double in C#

A deterministic game host often keeps positions as Q31.32: a 64-bit integer holding the value times 2^32. `FixedBridge` converts that raw `long` to and from `double` and `float` exactly where it can, rounds to nearest even where it must, and throws outside the range.

```shell
dotnet new console -o FixedPoint && cd FixedPoint
dotnet add package RecursiveAI.OneMath --version 1.0.0
```

Put this in `Program.cs` and run `dotnet run`:

```csharp
using RecursiveAI.OneMath;

// A deterministic host stores positions as Q31.32 raw longs (value * 2^32).
long x = FixedBridge.FromDouble(1234.5678);
Console.WriteLine($"raw {x}, back to double {FixedBridge.ToDouble(x):R}, as float {FixedBridge.ToSingle(x):R}");

// raw -> double -> raw is the identity for every raw value in range.
long[] raws = [1, -1, (1L << 53) - 1, 5_000_000_000];
double[] values = new double[raws.Length];
long[] again = new long[raws.Length];
FixedBridge.ToDouble(raws, values);
FixedBridge.FromDouble(values, again);
Console.WriteLine($"identity: {raws.SequenceEqual(again)}");

// Rounding: nearest, ties to even.
Console.WriteLine($"2^-33 -> {FixedBridge.FromDouble(Math.Pow(2, -33))}, 3*2^-33 -> {FixedBridge.FromDouble(3 * Math.Pow(2, -33))}");

// The range is |v| < 2^21.
Console.WriteLine($"bound {FixedBridge.ExclusiveMagnitudeBound}, in range 2e6: {FixedBridge.IsInRange(2e6)}, 3e6: {FixedBridge.IsInRange(3e6)}");
Console.WriteLine($"TryFromDouble(3e6): {FixedBridge.TryFromDouble(3e6, out _)}");
try { FixedBridge.FromDouble(double.NaN); }
catch (ArgumentOutOfRangeException e) { Console.WriteLine(e.Message); }
```

```text
raw 5302428325695, back to double 1234.567800000077, as float 1234.5677
identity: True
2^-33 -> 0, 3*2^-33 -> 2
bound 2097152, in range 2e6: True, 3e6: False
TryFromDouble(3e6): False
The value NaN is outside the exact range: it must be finite with magnitude below 2^21 = 2097152. (Parameter 'value')
Actual value was NaN.
```

## The rules

| Conversion | Result |
|---|---|
| raw to `double` (`ToDouble`) | `raw × 2^-32`, exact |
| raw to `float` (`ToSingle`) | the exact value rounded once to float, nearest, ties to even |
| `double` to raw (`FromDouble`) | `round(v × 2^32)`, nearest integer, ties to even; −0 gives 0 |
| `float` to raw (`FromSingle`) | widened to `double` (exact), then as above |

- The range is a finite value with |v| < 2^21 = 2,097,152, or a raw value with |raw| ≤ 2^53 − 1: 21 integer bits and 32 fractional bits are the 53 bits of a double’s significand, so every raw value in range is a double, and raw → double → raw is the identity.
- Outside it, `FromDouble` and `ToDouble` throw `ArgumentOutOfRangeException` naming the value and the bound; `TryFromDouble` and `TryToDouble` return false instead.
- The span forms convert in index order and throw on the first out-of-range element.

`2^-33` is exactly half a raw unit, so it rounds to the even neighbor, 0; `3 × 2^-33` is one and a half, and rounds to 2.

## Limits

- **A bridge, not a fixed-point type.** OneMath converts raw Q31.32 values; adding and multiplying them is up to your host or fixed-point library.
- **About ±2 million units.** Values at or beyond 2^21 don’t fit; scale the world or split it into regions.
- **`float` loses precision.** A `float` has 24 significant bits, so `ToSingle` rounds most raw values.

More in [the fixed-point bridge](https://recursiveai.org/onemath/docs/fixed-bridge/), including why float32 can’t hold every Q31.32 value.
