Hello Sergey,
<<So if the constructor [2] does not add an additional precision means that we
actually lost the precision. What will happen if the user will use a tiny
double parameters which is outside of your proposal? like 0.00000000000000001?
I said that constructor [1] adds extra unnecessary precision, but I did not say
that constructor [2] will remove the precision. It just keeps the precision to
same decimal places which we provide it. Following are few results of using
both constructors. So, the constructor [2] keeps the precision to same decimal
places we provided. It is not removing/decreasing any precision. After creation
of BigDecimal, we can do our calculations add/multiple and get the result using
BigDecimal.doubleValue(). fma is also doing these things only. Only difference
is they are creating BigDecimal using constructor[1].
I am not able to find any issue with this approach.
double a = .1
constructor [1]: 0.1000000000000000055511151231257827021181583404541015625
constructor [2]: 0.1
a = .0000001;
constructor [1]:
9.99999999999999954748111825886258685613938723690807819366455078125E-8
constructor [2]: 1.0E-7
a = .00000000000000001;
constructor [1]:
1.00000000000000007154242405462192450852805618492324772617063644020163337700068950653076171875E-17
constructor [2]: 1.0E-17
a = .0000000000000000000000001;
constructor [1]:
1.000000000000000038494869749191839081371989361591338301396127643500357819184021224145908490754663944244384765625E-25
constructor [2]: 1.0E-25
[1] new BigDecimal(double d)
[2] new BigDecimal(String s)
<<But it is possible to create Float.valueOf(float) and pass it to this
constructor, isn't it? this will work for any primitives.
<<[3] public SpinnerNumberModel(Number value,
Comparable<?> minimum,
Comparable<?> maximum,
Number stepSize)
Yes, it is true. If we create "Float" objects from primitive float and pass to
the constructor, things work fine. But what if the user is passing the
primitive float values directly? As the double constructor is there, it is
called instead of this constructor which accepts objects. This creates issue.
I don’t see this in spec that users should not use primitive float directly and
should first create "Float" object and then create SpinnerNumberModel. So they
will use primitive floats directly and run into these issues.
As I suggested earlier, either we should remove constructors with primitive
double or add constructor for primitive float.
Regards,
Pankaj Bansal
-----Original Message-----
From: Sergey Bylokhov
Sent: Wednesday, February 12, 2020 2:17 AM
To: Pankaj Bansal <[email protected]>; [email protected]
Subject: Re: <Swing Dev> [15] RFR JDK-8220811: SpinnerNumberModel floating
point rounding issue
On 2/11/20 3:40 am, Pankaj Bansal wrote:
> << Could you please try to use Math.fma instead of direct using of
> xxx.toString+BigDecimal I tried using this, but Math.fma will not solve our
> issue of precision here. Math.fma internally creates BigDecimal, but it uses
> the [1] type constructor to create the BigDecimal. The [1] constructor takes
> the primitive double value and it tries to represent the primitive double as
> precisely as possible and adds the extra precision. After the calculations in
> fma, the BigDecimal is rounded off to create double, but as it has very high
> precision, the issue in spinner is still there.
So if the constructor [2] does not add an additional precision means that we
actually lost the precision. What will happen if the user will use a tiny
double parameters which is outside of your proposal? like 0.00000000000000001?
I guess we should do the best to try not to lost a precision, and leave
rounding issues as-is since this is well just floating arithmetics which works
according the specification of SpinnerNumberModel.getNextValue: " @return
<code>value + stepSize</code> "
So we can use fma for the best result, or we could close this as not a bug.
> In my changes in webrev00, I have used the [2] form of constructor, which
> does not add extra precision and works fine for our case.
> I have created a dummy patch if you would like to try out this change
> with Math.fma
> (http://cr.openjdk.java.net/~pbansal/8220811/dummy.patch)
>
> [1] new BigDecimal(double d)
> [2] new BigDecimal(String s)
> https://stackoverflow.com/questions/7186204/bigdecimal-to-use-new-or-v
> alueof
>
>
>
> << Are you sure that it is necessary to add a new constructor? As far as I
> understand it is possible to pass a float value via:
> In java the implicit type promotion (auto-widening) is preferred over
> the auto boxing/unboxing. The SpinnerNumberModel has two constructors,
> one accepts all primitive "double" arguments [4] and other accepts
> Objects [3]. Now when SpinnerNumberModel is passed primitive "float"
> values, it looks for constructor which accepts all primitive floats.
> As such constructor is not available, it checks for alternatives. It
> has two alternates, either box the primitive "float" into object
> "Float" and call [3] or widen the primitive "float" to primitive
> "double". As auto widening is preferred over auto boxing, [4] is
> called instead of [3]. As I mentioned in previous mail, implicitly
> casting primitive float to primitive double adds precision issues
But it is possible to create Float.valueOf(float) and pass it to this
constructor, isn't it? this will work for any primitives.
[3] public SpinnerNumberModel(Number value,
Comparable<?> minimum,
Comparable<?> maximum,
Number stepSize)
--
Best regards, Sergey.