# Fixed Point Numbers

**URL:** <https://forum.ada-lang.io/t/fixed-point-numbers/1866>\
**Category:** General\
**Tags:** ada\
**Created:** [March 7, 2025, 6:01pm UTC](https://forum.ada-lang.io/t/fixed-point-numbers/1866 "2025-03-07T18:01:45Z")\
**Posts on this page:** 10\
**Page:** 2

<div class="post-metadata">

**Author:** ![JC001](https://forum.ada-lang.io/letter_avatar_proxy/v4/letter/j/e56c9b/32.png) [@JC001](https://forum.ada-lang.io/u/JC001)\
**Post date:** [March 10, 2025, 10:01am UTC](https://forum.ada-lang.io/t/fixed-point-numbers/1866/21 "2025-03-10T10:01:33Z")

</div>

> [@dmitry-kazakov](#):
>
> The correct type declaration would be:
> 
> `type Money is delta 0.01 digits 5; -- Decimal, 5 digits, not for you Elon!`
> 
> This one would work as expected and have 0.01 small.

In Ada 95 and later, yes, but for some reason Ada 95 wasn’t available in 1984.

---

<div class="post-metadata">

**Author:** ![dmitry-kazakov](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/dmitry-kazakov/32/522_2.png) [@dmitry-kazakov](https://forum.ada-lang.io/u/dmitry-kazakov)\
**Post date:** [March 10, 2025, 10:55am UTC](https://forum.ada-lang.io/t/fixed-point-numbers/1866/22 "2025-03-10T10:55:50Z")

</div>

Ah, I forgot that digits was 95 addition.

---

<div class="post-metadata">

**Author:** ![simonjwright](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/simonjwright/32/11_2.png) [@simonjwright](https://forum.ada-lang.io/u/simonjwright)\
**Post date:** [March 10, 2025, 2:50pm UTC](https://forum.ada-lang.io/t/fixed-point-numbers/1866/23 "2025-03-10T14:50:42Z")

</div>

> [@dmitry-kazakov](#):
>
> > [@simonjwright](#):
> >
> > what difference does it make if the scale is 0.1 or 0.0625?
> 
> Let you multiply two binary fixed-point numbers on a binary machine. 0.0625 = 1/32 = 1/2\*\*5 is a power of 2.

In (most, if not all) modern machines the scale of a fixed-point number is a construct in the mind of the programmer. What you have are plain old integers, and you might choose to interpret the LSB as having value 0.1 (1/10) say, or 0.0625 (1/16). If you multiply one of each together, you’ll get a (double-length) product where the LSB has value 1/160. Most of the pain of fixed-point multiplication is working out how you want to deal with that product; of division, how you want to present the dividend to the machine’s divide hardware to get the result you need.

---

<div class="post-metadata">

**Author:** ![dmitry-kazakov](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/dmitry-kazakov/32/522_2.png) [@dmitry-kazakov](https://forum.ada-lang.io/u/dmitry-kazakov)\
**Post date:** [March 10, 2025, 3:09pm UTC](https://forum.ada-lang.io/t/fixed-point-numbers/1866/24 "2025-03-10T15:09:24Z")

</div>

But you cannot multiply values of two different fixed-point types anyway.

But in any case the point stands. If your scale is a power of the machine radix you can implement fixed-point multiplication and division using shifts in that radix.

---

<div class="post-metadata">

**Author:** ![simonjwright](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/simonjwright/32/11_2.png) [@simonjwright](https://forum.ada-lang.io/u/simonjwright)\
**Post date:** [March 10, 2025, 4:43pm UTC](https://forum.ada-lang.io/t/fixed-point-numbers/1866/25 "2025-03-10T16:43:26Z")

</div>

> [@dmitry-kazakov](#):
>
> But you cannot multiply values of two different fixed-point types anyway.

Oh yes you can. You “merely” have to deal with the scaling of the result.

```ada
with Ada.Text_IO; use Ada.Text_IO;
procedure Fixed is
   type Dec is delta 0.1 range 0.0 .. 5.0 with
     Small => 0.1;
   type Fix is delta 0.1 range 0.0 .. 5.0;
   Product_Delta : constant := Dec'Small * Fix'Small;
   type Product is delta Product_Delta range 0.0 .. 25.0 with
     Small => Product_Delta;
   Half_Product_Delta : constant := Product_Delta / 2.0;
   type Short_Product is delta Half_Product_Delta range 0.0 .. 25.0 with
     Small => Half_Product_Delta;
   D : Dec := 0.7;
   F : Fix := 0.7;
begin
   Put_Line (Product'(D * F)'Image);
   Put_Line (Short_Product'(D * F)'Image);
end Fixed;

```

Both outputs are 0.481 (obviously _should_ be 0.49, but it’s that `F’(0.7)`).

> [@](#):
>
> But in any case the point stands. If your scale is a power of the machine radix you can implement fixed-point multiplication and division using shifts in that radix.

In the example I gave above, the compiler can generate the `Product` result by taking the unaltered output of the multiplication. To generate the `Half_Product` result it would have to shift the output up one place. If you decided to assign the result to a type with a `’Small` that wasn’t a binary multiple, say `Product_Delta / 3.0`, the compiler would have to scale the result to match (in that case, multiplying the multiplication’s output by 3).

---

<div class="post-metadata">

**Author:** ![dmitry-kazakov](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/dmitry-kazakov/32/522_2.png) [@dmitry-kazakov](https://forum.ada-lang.io/u/dmitry-kazakov)\
**Post date:** [March 10, 2025, 5:40pm UTC](https://forum.ada-lang.io/t/fixed-point-numbers/1866/26 "2025-03-10T17:40:39Z")

</div>

> [@simonjwright](#):
>
> Oh yes you can. You “merely” have to deal with the scaling of the result.

OK, I get _universal\_fixed_ which is a rational number.

Compare code generated for decimal and binary fixed-point:

```ada
   type Dec is delta 0.1 digits 2 range 0.0 .. 5.0;
   type Fix is delta 0.1 range 0.0 .. 5.0;

   D : Dec := 0.7;
   F : Fix := 0.7;
begin
   D := D * D;
   F := F * F;

```

You need a lot more for the decimal one because the machine radix is 2.

---

<div class="post-metadata">

**Author:** ![kevlar700](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/kevlar700/32/1118_2.png) [@kevlar700](https://forum.ada-lang.io/u/kevlar700)\
**Post date:** [December 3, 2025, 4:26pm UTC](https://forum.ada-lang.io/t/fixed-point-numbers/1866/27 "2025-12-03T16:26:53Z")

</div>

> [@JC001](#):
>
> These days, with floating-point hardware common, fixed-point types are primarily useful for interfacing with hardware that uses scaled integers (as in Wright’s post), and for currencies.

It’s still quite common for C programmers on microchips to avoid using the single precision FPU due to the hazards of it’s limited range and multiply and divide larger numbers. There are blogs about Cs fixed point libraries being full of dragons too. In that light then Adas fixed point support is a God send. I hear A.I. is using half precision 😆 and wonder if that affects A.I. inaccuracies further.

---

<div class="post-metadata">

**Author:** ![TerryFroggatt](https://forum.ada-lang.io/letter_avatar_proxy/v4/letter/t/94ad74/32.png) [@TerryFroggatt](https://forum.ada-lang.io/u/TerryFroggatt)\
**Post date:** [January 8, 2026, 12:50pm UTC](https://forum.ada-lang.io/t/fixed-point-numbers/1866/28 "2026-01-08T12:50:16Z")

</div>

Apologies for this late contribution, I recently  
saw this thread reprinted in the Ada User Journal.

In Ada 83, it was a requirement to provide power-of-two 'smalls,  
whereas providing for other values of 'small was an option.  
Providing the power-of-two scalings which meet Ada’s model  
number requirements was straightforward, using shifts.

As Simon Wright has said, you can multiply any two different fixed-point  
types: ‘you “merely” have to deal with the scaling of the result’.  
Performing both the requested multiply (or divide) operation  
and a second operation for the scaling (often not just a shift),  
all within Ada’s model number requirements, was diffcult.

Essentially it required triple-length arithmetic at worst, but  
hardware usually provides double-length products at best. I’m not  
sure if those vendors who chose to implement the optional arbitrary  
'small arithmetic in Ada 83 did so correctly, and how slow it was.

This problem was recognised in Ada 95 in two ways.  
Firstly “relaxed mode” was introduced.  
Secondly, even in “strict mode”, the accuracy requirements  
were relaxed (see Ada 95 LRM K.2.3 now Ada 2022 LRM G.2.3).  
The default use of power-of-two was retained for compatability.

---

<div class="post-metadata">

**Author:** ![sttaft](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/sttaft/32/12_2.png) [@sttaft](https://forum.ada-lang.io/u/sttaft)\
**Post date:** [January 12, 2026, 7:15pm UTC](https://forum.ada-lang.io/t/fixed-point-numbers/1866/29 "2026-01-12T19:15:47Z")

</div>

Great to hear from you Terry. In practice, essentially all Ada compilers now support arbitrary “small”s for fixed-point types, and do the “right thing” using integer arithmetic as appropriate. For a while GNAT was using floating-point arithmetic in some cases, but I believe GNAT only uses integer arithmetic now.

---

<div class="post-metadata">

**Author:** ![MarioBlunk](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/marioblunk/32/462_2.png) [@MarioBlunk](https://forum.ada-lang.io/u/MarioBlunk)\
**Post date:** [February 10, 2026, 5:24pm UTC](https://forum.ada-lang.io/t/fixed-point-numbers/1866/30 "2026-02-10T17:24:00Z")

</div>

A good example of how important fixed point numbers in the real world are is a ruler. Its scale “uses” fixed point numbers. The error is constant, independent of the actual distance being measured. So a lot of CAD-systems need to output fixed point numbers with a constant ‘small.

[Previous page](https://forum.ada-lang.io/t/fixed-point-numbers/1866.md?page=1)
