5
$\begingroup$

Fixed point is essentially storing a number of units of a certain size instead of storing a significand and an exponent. However, if the units could be of any size, how big would the fixed-point units be in a typical fixed type of a programming language? C does not have fixed-point, so to use this one just stores an integer and divides by the number of units in a 1 to get the value, for example, one could store an angle as a uint16_t x; representing 65536ths of a turn, and call sinpif(x*0x1p-15F). However, if a language were to implement proper fixed-point semantics, how could this be done? What would be a typical range and precision of the varying fixed-point types?

$\endgroup$

5 Answers 5

6
$\begingroup$

Fixed-point is an integer with a statically-known decimal (or more generally, statically-known divisor). You can represent a fixed-point datatype as an "representation" integer type and "divisor" integer (kind of like a fixed-sized array, which is an "element" type and statically-known "length" integer). At runtime, the value is simply an integer, but the compiler uses the statically-known divisor to do proper conversion (e.g. to floating-point or string).

For example, imagine a language with this syntax

type Currency = FixedPoint<u32, 100>

let currency1: Currency = 50.34  # represented as 5034
let currency2: Currency = 123.9  # represented as 12390
let currency3: Currency = currency1 + currency2  # represented as 17424
print(currency3)  # prints 174.24

Note that there isn't one "fixed-point" type, since different types may opt for different fixed points. The key difference between these types and a floating-point type, is that all instances of a particular fixed point type have the same "decimal" or divisor (whereas floating-points the decimal can be at different points at runtime).


I actually don't know any real-world languages which implement this feature, though. The closest may be F#, which has measurement types. For your specific example, you could declare a [<Measure>] type angle, and then ensure that int16<angle> n is treated as n 2*pi/65536 radians like so:

[<Measure>] type angle

let toRadians (x: int16<angle>) = x * 2 * pi / 65536<angle>

Then you can't use int16<angle> wherever a unit type is expected, you must apply toRadians first.

$\endgroup$
2
  • $\begingroup$ For real-world uses of fixed-point arithmetic, a good place to look is probably assembly languages for digital signal processing chips. Fixed point numbers are used a lot in DSP. $\endgroup$
    – kaya3
    May 20, 2023 at 19:12
  • $\begingroup$ COBOL has fixed-point arithmetic. The reason some programmers care about fixed-point arithmetic is that it's used in the real world! $\endgroup$ May 20, 2023 at 20:50
5
$\begingroup$

Make precision part of the type

I’m not familiar with any general-purpose languages that use fixed point at all, but this is what PostgreSQL does. If you want to indicate that a column stores 15 digits, of which two are to the right of the decimal point, type it as NUMERIC(15, 2). This way, each user can choose a reasonable scale for their application, instead of the language forcing one on them.

$\endgroup$
3
$\begingroup$

Have a default precision, and allow changing it

Lisp has several different types of floats. One is long-float, with arbritrary precision. For example:

(SETF (EXT:LONG-FLOAT-DIGITS) 3322)

This sets the "long float" precision to 3322 binary digits (approximately 1000 decimal digits). By default, it's 64 binary digits.

After this, you can print out a long float to see that it works: Try it online!

$\endgroup$
3
$\begingroup$

GCC Fixed-Point Types

GCC has fixed point types as an extension. The types are _Fract and _Accum (A new language would designate them as just fract and accum) and could be combined with long short etc to specify precision, and unsigned to specify signedness.

fract

A fract would store a normalized value between [0, 1). The increments would be 1/2^bits where bits is bits of precision. If signed, one of the bits would be a sign bit so the increments would be twice as big.

accum

An accum would store half the bits as integer bits and half as fraction bits. The range would be [0, 2^(bits/2)) but in increments of 1/2^(bits/2).

$\endgroup$
2
$\begingroup$

Ada has fixed-point numbers: https://www.adaic.org/resources/add_content/standards/05rm/html/RM-3-5-9.html

The given examples are

type Volt is delta 0.125 range 0.0 .. 255.0;

  -- A pure fraction which requires all the available
  -- space in a word can be declared as the type Fraction:
type Fraction is delta System.Fine_Delta range -1.0 .. 1.0;
  -- Fraction'Last = 1.0 – System.Fine_Delta

type Money is delta 0.01 digits 15;  -- decimal fixed point
subtype Salary is Money digits 10;
  -- Money'Last = 10.0**13 – 0.01, Salary'Last = 10.0**8 – 0.01

There's two alternatives; a normal fixed-point type uses a power of two as its delta, and a decimal fixed-point type uses a power of ten.

$\endgroup$
2
  • $\begingroup$ The question is not what languages have fixed point but how you might implement it for your own language $\endgroup$
    – mousetail
    May 20, 2023 at 19:17
  • $\begingroup$ @mousetail This shows the same details as the Lisp and SQL examples above. They're all examples of how the syntax could work, and certainly for binary fixed-point, the implementations pretty trivial; shift everything by the appropriate power of two on literals and conversions, don't worry about add and subtract, and do the obvious modifications on multiply and divide. $\endgroup$
    – prosfilaes
    May 20, 2023 at 19:21

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .