Skip to content

Commit 630cfde

Browse files
vk2sebzyp
authored andcommitted
Unresolved: add a proposal to all unresolved questions from original RFC
1 parent 09c21a1 commit 630cfde

File tree

1 file changed

+14
-2
lines changed

1 file changed

+14
-2
lines changed

text/0041-fixed-point.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ The following operations are defined on it:
3737
- A `fixed.Shape` may be constructed using the following aliases:
3838
- `SQ(i_bits, f_bits)` is an alias for `fixed.Shape(signed(i_bits + f_bits), f_bits)`.
3939
- `UQ(i_bits, f_bits)` is an alias for `fixed.Shape(unsigned(i_bits + f_bits), f_bits)`.
40-
- `fixed.Shape.cast(shape, f_bits=0)`: Cast `shape` to a `fixed.Shape` instance.
4140
- `.i_bits`, `.f_bits`, `.signed`: Width and signedness properties of the `fixed.Shape`.
4241
- `.i_bits` includes the sign bit. That is, for `fixed.Shape(signed(16), 12)`, `.i_bits == 4`.
4342
- `.const(value)`: Create a `fixed.Const` from `value`.
@@ -67,7 +66,7 @@ The following operations are defined on it:
6766
- `.__add__(other)`, `.__radd__(other)`, `.__sub__(other)`, `.__rsub__(other)`, `.__mul__(other)`, `.__rmul__(other)`: Binary arithmetic operators.
6867
- If `other` is a `Value`, it'll be cast to a `fixed.Value` first.
6968
- If `other` is an `int`, it'll be cast to a `fixed.Const` first.
70-
- If `other` is a `float`: TBD
69+
- If `other` is a `float`, this is not permitted. The `float` must be explicitly cast to `fixed.Const`.
7170
- The result will be a new `fixed.Value` with enough precision to hold any resulting value without rounding or overflowing.
7271
- `.__lshift__(other)`, `.__rshift__(other)`: Bit shift operators.
7372
- `other` only accepts integral types. For example, shifting by a `float` or `fixed.Value` is not permitted.
@@ -128,22 +127,29 @@ TBD
128127
However, since a Python `float` is double precision, this means it's easy to make a >50 bit number by accident by doing something like `value * (1 / 3)`, and even if the result is rounded or truncated afterwards, the lower bits can affect rounding and thus won't be optimized out in synthesis.
129128
- We could use the same width for `other` as for `self`, adjusted to the appropriate exponent for the value.
130129
- We could outright reject it, requiring the user to explicitly specify precision like e.g. `value * Q(15).const(1 / 3)`.
130+
- vk2seb@: I would lean toward outright rejecting this, with an explicit cast necessary (now reflected above).
131131

132132
- How should we handle rounding?
133133
- Truncating and adding the most significant truncated bit is cheap and is effectively round to nearest with ties rounded towards positive infinity.
134134
- Simply truncating is free, rounds towards negative infinity.
135135
- IEEE 754 defaults to round to nearest, ties to even, which is more expensive to implement.
136136
- Should we make it user selectable?
137137
- We still need a default mode used when a higher precision number is passed to `.eq()`.
138+
- vk2seb@: Both truncation and simple rounding (round to nearest) are commonly used in DSP algorithms. For now, we provide only `truncate()` and `round()` strategies (now reflected above). Additional rounding strategies may be added in a future RFC, however we will always need a default rounding strategy.
138139

139140
- Are there any other operations that would be good to have?
141+
- From ld-cd@: `min()`, `max()` on `fixed.Shape` (vk2seb@: agree, heavily use this)
142+
- From ld-cd@: `numerator()` as a signedness-preserving `as_value()` (vk2seb@: agree, heavily use this)
143+
- vk2seb@: Let's add both of these operations (now reflected above)
140144

141145
- Are there any operations that would be good to *not* have?
142146
- This API (`fixed.Shape.cast()`) seems confusing and difficult to use. Should we expose it at all? (@whitequark)
147+
- vk2seb@: It can survive as a building block but I don't see why it needs to be exposed. Propose removal (reflected above).
143148

144149
- `Decimal` and/or `Fraction` support?
145150
- This could make sense to have, but both can represent values that's not representable as binary fixed point.
146151
On the other hand, a Python `float` can perfectly represent any fixed point value up to a total width of 53 bits and any `float` value is perfectly representable as fixed point.
152+
- vk2seb@: As both can represent values that aren't representable as binary fixed point, I don't see a huge benefit. I also can't immediately think of an application that would need >53 bit constants. I would propose for now we leave `Decimal` and `Fraction` out of scope of this RFC.
147153

148154
- Name all the things.
149155
- Library name:
@@ -154,6 +160,12 @@ TBD
154160
- `.int_bits`, `.frac_bits`?
155161
- cursed option: `int, frac = x.width`?
156162
- `.round()` is a bit awkwardly named when it's used both to increase and decrease precision.
163+
- vk2seb@: The existing modifications address this:
164+
- Library name: `lib.fixed`
165+
- Type names and shapes: signature has now been updated to use `i_bits`, `f_bits` and the explicit underlying storage in the constructor for `fixed.Shape`.
166+
- We now have both `.round()` and `.truncate()`. I don't think using the same name for increasing and decreasing precision is so bad. But if you feel strongly about this we may consider:
167+
- Renaming them.
168+
- Disallowing increasing precision with these methods, and add a new method for precision extension .
157169

158170
## Future possibilities
159171
[future-possibilities]: #future-possibilities

0 commit comments

Comments
 (0)