FixedPointDecimals.jl icon indicating copy to clipboard operation
FixedPointDecimals.jl copied to clipboard

FD{BigInt} operations currently allocate more than necessary due to promotion.

Open NHDaly opened this issue 2 years ago • 1 comments

Consider:

julia> @which FD{BigInt,2}(2) + 2
+(x::Number, y::Number)
     @ Base promotion.jl:410

julia> @code_typed FD{BigInt,2}(2) + 2
CodeInfo(
1 ─ %1 = invoke Base.GMP.MPZ.set_si(10::Int64)::BigInt
│   %2 = invoke Base.GMP.bigint_pow(%1::BigInt, 2::Int64)::BigInt
│   %3 = invoke Base.GMP.MPZ.mul_si(%2::BigInt, y::Int64)::BigInt
│   %4 = Base.getfield(x, :i)::BigInt
│   %5 = invoke Base.GMP.MPZ.add(%4::BigInt, %3::BigInt)::BigInt
│   %6 = %new(FixedDecimal{BigInt, 2}, %5)::FixedDecimal{BigInt, 2}
└──      return %6
) => FixedDecimal{BigInt, 2}

julia> @code_typed optimize=false FD{BigInt,2}(2) + 2
CodeInfo(
1 ─ %1 = Base.:+::Core.Const(+)
│   %2 = Base.promote(x, y)::Tuple{FixedDecimal{BigInt, 2}, FixedDecimal{BigInt, 2}}
│   %3 = Core._apply_iterate(Base.iterate, %1, %2)::FixedDecimal{BigInt, 2}
└──      return %3
) => FixedDecimal{BigInt, 2}

If we instead had special-cased operators for ::FD{BigInt}, ::Integer we could avoid the promotion and save an allocation.

NHDaly avatar Dec 18 '23 23:12 NHDaly

This actually also leads to the fact that operators can throw InexactErrors, while promoting the other arguments:

julia> FixedDecimal{Int8,2}(1) + 2  # 2 is promoted to FD{Int8,2}(2), which doesn't fit!
ERROR: InexactError: convert(FixedDecimal{Int8, 2}, 2)

NHDaly avatar Dec 19 '23 00:12 NHDaly