lilliput_float/
floats.rs

1/// A bit-level representation of a 8-bit floating-point number.
2///
3/// The bits are laid out as follows:
4/// - Sign bit: 1 bit
5/// - Exponent width: 4 bits
6/// - Significand precision: 4 bits (3 explicitly stored)
7///
8/// ```plain
9///  MSB   ...   LSB
10/// ┌─┬─┬─┬─┬─┬─┬─┬─┐
11/// └─┴─┴─┴─┴─┴─┴─┴─┘
12///  │ ├─────┘ ├───┘
13///  │ │       └ Significand (3 bits)
14///  │ └ Exponent (4 bits)
15///  └ Sign (1 bit)
16///  ```
17#[derive(Default, Copy, Clone)]
18#[repr(transparent)]
19pub struct F8(pub(crate) u8);
20
21impl std::fmt::Debug for F8 {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        write!(f, "{:08b}", self.0)
24    }
25}
26
27/// A bit-level representation of a 16-bit floating-point number.
28///
29/// The bits are laid out as follows:
30/// - Sign bit: 1 bit
31/// - Exponent width: 5 bits
32/// - Significand precision: 11 bits (10 explicitly stored)
33///
34/// ```plain
35///  MSB           ...           LSB
36/// ┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
37/// └─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
38///  │ ├───────┘ ├─────────────────┘
39///  │ │         └ Significand (10 bits)
40///  │ └ Exponent (5 bits)
41///  └ Sign (1 bit)
42///  ```
43#[derive(Default, Copy, Clone)]
44#[repr(transparent)]
45pub struct F16(pub(crate) u16);
46
47impl std::fmt::Debug for F16 {
48    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49        write!(f, "{:016b}", self.0)
50    }
51}
52
53/// A bit-level representation of a 24-bit floating-point number.
54///
55/// The bits are laid out as follows:
56/// - Sign bit: 1 bit
57/// - Exponent width: 7 bits
58/// - Significand precision: 17 bits (16 explicitly stored)
59///
60/// ```plain
61///  MSB                      ...                     LSB
62/// ┌─┬╴╴┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
63/// └─┴╴╴┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
64///  ├╴╴┘ │ ├───────────┘ ├─────────────────────────────┘
65///  │    │ │             └ Significand (16 bits)
66///  │    │ └ Exponent (7 bits)
67///  │    └ Sign (1 bit)
68///  └ Padding (8 bits)
69///  ```
70#[derive(Default, Copy, Clone)]
71#[repr(transparent)]
72pub struct F24(pub(crate) u32);
73
74impl std::fmt::Debug for F24 {
75    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76        write!(f, "{:024b}", self.0)
77    }
78}
79
80/// A bit-level representation of a 32-bit floating-point number.
81///
82/// The bits are laid out as follows:
83/// - Sign bit: 1 bit
84/// - Exponent width: 8 bits
85/// - Significand precision: 24 bits (23 explicitly stored)
86///
87/// ```plain
88///  MSB                              ...                             LSB
89/// ┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
90/// └─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
91///  │ ├─────────────┘ ├───────────────────────────────────────────┘
92///  │ │               └ Significand (23 bits)
93///  │ └ Exponent (8 bits)
94///  └ Sign (1 bit)
95///  ```
96#[derive(Default, Copy, Clone)]
97#[repr(transparent)]
98pub struct F32(pub(crate) u32);
99
100impl std::fmt::Debug for F32 {
101    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102        write!(f, "{:032b}", self.0)
103    }
104}
105
106/// A bit-level representation of a 40-bit floating-point number.
107///
108/// The bits are laid out as follows:
109/// - Sign bit: 1 bit
110/// - Exponent width: 8 bits
111/// - Significand precision: 32 bits (31 explicitly stored)
112///
113/// ```plain
114///  MSB                              ...                             LSB
115/// ┌─┬╴╴┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬╴╴╴┬─┐
116/// └─┴╴╴┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴╴╴╴┴─┘
117///  ├╴╴┘ │ ├─────────────┘ ├───────────────────────────────────────╴╴╴─┘
118///  │    │ │               └ Significand (31 bits)
119///  │    │ └ Exponent (8 bits)
120///  │    └ Sign (1 bit)
121///  └ Padding (24 bits)
122///  ```
123#[derive(Default, Copy, Clone)]
124#[repr(transparent)]
125pub struct F40(pub(crate) u64);
126
127impl std::fmt::Debug for F40 {
128    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129        write!(f, "{:040b}", self.0)
130    }
131}
132
133/// A bit-level representation of a 48-bit floating-point number.
134///
135/// The bits are laid out as follows:
136/// - Sign bit: 1 bit
137/// - Exponent width: 9 bits
138/// - Significand precision: 39 bits (38 explicitly stored)
139///
140/// ```plain
141///  MSB                              ...                             LSB
142/// ┌─┬╴╴┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬╴╴╴┬─┐
143/// └─┴╴╴┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴╴╴╴┴─┘
144///  ├╴╴┘ │ ├───────────────┘ ├─────────────────────────────────────╴╴╴─┘
145///  │    │ │                 └ Significand (38 bits)
146///  │    │ └ Exponent (9 bits)
147///  │    └ Sign (1 bit)
148///  └ Padding (16 bits)
149///  ```
150#[derive(Default, Copy, Clone)]
151#[repr(transparent)]
152pub struct F48(pub(crate) u64);
153
154impl std::fmt::Debug for F48 {
155    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
156        write!(f, "{:048b}", self.0)
157    }
158}
159
160/// A bit-level representation of a 56-bit floating-point number.
161///
162/// The bits are laid out as follows:
163/// - Sign bit: 1 bit
164/// - Exponent width: 10 bits
165/// - Significand precision: 46 bits (45 explicitly stored)
166///
167/// ```plain
168///  MSB                              ...                             LSB
169/// ┌─┬╴╴┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬╴╴╴┬─┐
170/// └─┴╴╴┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴╴╴╴┴─┘
171///  ├╴╴┘ │ ├─────────────────┘ ├───────────────────────────────────╴╴╴─┘
172///  │    │ │                   └ Significand (45 bits)
173///  │    │ └ Exponent (10 bits)
174///  │    └ Sign (1 bit)
175///  └ Padding (8 bits)
176///  ```
177#[derive(Default, Copy, Clone)]
178#[repr(transparent)]
179pub struct F56(pub(crate) u64);
180
181impl std::fmt::Debug for F56 {
182    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
183        write!(f, "{:056b}", self.0)
184    }
185}
186
187/// A bit-level representation of a 64-bit floating-point number.
188///
189/// The bits are laid out as follows:
190/// - Sign bit: 1 bit
191/// - Exponent width: 11 bits
192/// - Significand precision: 53 bits (52 explicitly stored)
193///
194/// ```plain
195///  MSB                           ...                           LSB
196/// ┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬╴╴╴┬─┐
197/// └─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴╴╴╴┴─┘
198///  │ ├─────────────────┘ ├───────────────────────────────────╴╴╴─┘
199///  │ │                   └ Significand (53 bits)
200///  │ └ Exponent (11 bits)
201///  └ Sign (1 bit)
202///  ```
203#[derive(Default, Copy, Clone)]
204#[repr(transparent)]
205pub struct F64(pub(crate) u64);
206
207impl std::fmt::Debug for F64 {
208    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209        write!(f, "{:064b}", self.0)
210    }
211}