You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is how multiplication of fractional values works in binary numbers:
multiplying two numbers with i1 and i2 (possibly leading zeros, possibly sign-including) integer bits, the result will have at most i1 + i2 integer bits.
multiplying two numbers with f1 and f2 (possibly trailing zeros) fractional digits, the result will have at most f1 + f2 fractional bits.
So the only general, type-safe definition (independent of the values) which is aligned to "doubling the number of bits from Base" is the definition of the result type to have i1 + i2 integer bits and f1 + f2 fractional bits.
With a top-down approach, OP seems correct. On the other hand, with a bottom-up approach, a different definition also seems reasonable.
Fixed-point numbers possess characteristics intermediate between integers and floating-point numbers. If both behave in the same way, it is implicitly expected that fixed-point numbers will also behave similarly.
For the sake of simplicity, let us first consider the case where the types of the two operands are identical.
For *, the output type is the same as the input type.
The reasoning in the comment above breaks down when the operands are Fixed or Normed types with different fractional bits f.
However, this does not mean that the bottom-up approach is incorrect. Rather, it is a practical issue with the top-down definition.
Attempting to satisfy both dynamic range and precision easily leads to the use of 128-bit types, marking the end of the road.
For this reason, the current promotion_rule is based on max(f1, f2) rather than f1 + f2.
Three variants can be considered here:
Define widemul only when the two operands have completely identical types.
widen is the additive widening that needs one additional bit for identical BitIntegers, but, per convention and for pragmatic reasons, doubles the size of Base.BitInteger64_types.
widemul is the multiplicative widening that (besides actually doing the multiplication) really needs twice the number of bits for identical BitIntegers.
So widemul is no variant of widen (in the sense that you cannot use either to reason about the other) as much as one (multiplicative identity) is not a variant of oneunit (one-unit step value).
promote and promote_rule are a third thing which only demand a common type. It neither needs to be wide enough for addition nor for multiplication.
As already written: You can define different interfaces/contracts, and there are quite some useful definitions, but then it's no longer widemul, but a different function (e.g. Base.mul_hi).
Ultimately, since your explanation is based on a top-down definition, it serves only to reinforce the "correctness" of the OP.
I am (or the second post is) not denying that the definition in the OP.
The point here should be practicality rather than correctness.
From a practical standpoint, the fact remains that, regardless of which definition is adopted, the implementation of widemul for Normed is inherently cumbersome.
If manually performing type conversions or using Float16 or Float32 is considered best practice, then the point of implementing widemul is undermined.
On the other hand, while Fixed also involves rounding issues, shifting the decimal point position is not particularly complex.
Paradoxically, I don't think people are clamoring for widemul for Fixed.
IMO, not implementing widemul is a reasonable option.
Activity
kimikage commentedon Oct 10, 2026
With a top-down approach, OP seems correct. On the other hand, with a bottom-up approach, a different definition also seems reasonable.
Fixed-point numbers possess characteristics intermediate between integers and floating-point numbers. If both behave in the same way, it is implicitly expected that fixed-point numbers will also behave similarly.
For the sake of simplicity, let us first consider the case where the types of the two operands are identical.
For
*, the output type is the same as the input type.Of course, the situation regarding
*cannot be said to be entirely clear. There have been similar discussions in the past.(cf. #227 (comment))Next, let's look at
widemul, which could be considered a variant of*.widen(Q7f8)is expected to result inQ23f8(because it is based on addition/subtraction rather than multiplication), and it differs fromQ15f16.kimikage commentedon Oct 10, 2026
The reasoning in the comment above breaks down when the operands are
FixedorNormedtypes with different fractional bitsf.However, this does not mean that the bottom-up approach is incorrect. Rather, it is a practical issue with the top-down definition.
Attempting to satisfy both dynamic range and precision easily leads to the use of 128-bit types, marking the end of the road.
For this reason, the current
promotion_ruleis based onmax(f1, f2)rather thanf1 + f2.Three variants can be considered here:
widemulonly when the two operands have completely identical types.widemulonly whenf1 == f2.widemulfor all cases with promotion.PatrickHaecker commentedon Oct 11, 2026
Sorry, I couldn't follow your argumentation here.
widenis the additive widening that needs one additional bit for identicalBitIntegers, but, per convention and for pragmatic reasons, doubles the size ofBase.BitInteger64_types.widemulis the multiplicative widening that (besides actually doing the multiplication) really needs twice the number of bits for identicalBitIntegers.So
widemulis no variant ofwiden(in the sense that you cannot use either to reason about the other) as much asone(multiplicative identity) is not a variant ofoneunit(one-unit step value).promoteandpromote_ruleare a third thing which only demand a common type. It neither needs to be wide enough for addition nor for multiplication.As already written: You can define different interfaces/contracts, and there are quite some useful definitions, but then it's no longer
widemul, but a different function (e.g.Base.mul_hi).kimikage commentedon Oct 11, 2026
Ultimately, since your explanation is based on a top-down definition, it serves only to reinforce the "correctness" of the OP.
I am (or the second post is) not denying that the definition in the OP.
The point here should be practicality rather than correctness.
From a practical standpoint, the fact remains that, regardless of which definition is adopted, the implementation of
widemulforNormedis inherently cumbersome.If manually performing type conversions or using
Float16orFloat32is considered best practice, then the point of implementingwidemulis undermined.On the other hand, while
Fixedalso involves rounding issues, shifting the decimal point position is not particularly complex.Paradoxically, I don't think people are clamoring for
widemulforFixed.IMO, not implementing
widemulis a reasonable option.kimikage commentedon Oct 11, 2026
@timholy might have some strong opinions on "widen arithmetic."