ericmj / decimal

Arbitrary precision decimal arithmetic

Home Page:https://hexdocs.pm/decimal/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Why should we use Decimal.from_float explicitly

seamon opened this issue · comments

  • Deprecate passing float to Decimal.new/1 in favor of Decimal.from_float/1

This feature coming along with 1.6.0, but I don't understand why we should do that.

In my project, parameters in many functions may be integer or float, I can use D.new to deal with these numbers, but now I have to write and use another function to see what the number is, to decide to call D.new or D.from_float, that's exactly the former 1.5 version did: D.new(any-number)

def new(int) when is_integer(int),
  do: %Decimal{sign: if(int < 0, do: -1, else: 1), coef: Kernel.abs(int)}

def new(float) when is_float(float) do
  from_float(float)
end

Why should we use D.from_float explicitly? What's the benefit of doing that

Thank you so much.

The reason is to make it explicit that you are doing a lossy conversion, the implementation is still the same internally.

Thanks for your quick reply.

But it's really inconvenient... So many codes need to be changed to distinguish integer and float. Is there any chance to give it back? ^_^

Or is there any way noninvasive to remind the lossy conversion? ie. just warning such as D.new(0.001) and D.new(:math.pow(10, 2)) in compile time, instead of hard coded IO.warn in runtime.

We can't do a reliable warning at compile time unfortunately, and I would only introduce a warning if the plan is to make it an error in the future.

If you are fine with a lossy conversion then I think it's nice that you have showed explicitly in the code that you have considered the dangers of using floats for decimal calculations.

Got it. I'll figure it out. Thank you so much.

Could we have a function that is explicitly lossy for floats, but also allows and accepts integers (and nil)? This would be instead of having to do a check every time like:

      case acres do
        value when is_float(value) -> Decimal.from_float(value)
        value when is_integer(value) -> Decimal.new(value)
        _ -> Decimal.new(0)
      end

I believe accepting both integers and floats (for reasons mentioned above) and automatically converting nil to Decimal.new(0) may make sense for your app but shouldn't be part of Decimal as some users might expect that but some don't. I'd suggest to create a function specific to your project that does just that!

Fair enough, thank you for the consideration