Adding BigDecimal.valueOf(float val) constructor

Raffaello Giulietti raffaello.giulietti at oracle.com
Fri Jan 24 11:42:16 UTC 2025


Hi Jan,

just to note that the benchmark results only measure the case 0.1f. For 
more general floats, the perf gains might look less impressive (but I 
didn't check).

Anyway, a fresh name seems to be the less risky solution, if we agree 
that the problem is widespread enough to justify adding the new 
fromFloat() factory method.


R



On 2025-01-24 12:11, Jan Kowalski wrote:
> Thank you all for your replies!
> 
> I'm aware of the workaround (we are using this approach in our project) 
> and the problematic issues with decimal conversions. However, I also 
> think that we should make sure that the behaviour of the code is more 
> predictable. For me and other developers, it might be confusing that 
> values of /new BigDecimal(Float.toString(val))/, and then / 
> BigDecimal.valueOf(double val)/ are different. I'd say that, if it's 
> possible, we should reduce the arithmetic artifacts, rather than 
> introduce them through not really needed, and not visible at the first 
> sight, type conversions.
> 
> Unfortunately, I was aware about potential backwards compatibility 
> issues and I was curious what is your opinion on this (I also thought 
> about introducing a factory method like fromFloat to eliminate it, but 
> I'm not sure if it sounds like a good idea). Do you think introducing 
> such change would be beneficial to simplify the code, or rather 
> introduce minor precision improvement, while we still don't have 100% 
> decimal precision?
> 
> Also out of curiosity I ran a benchmark on how lack of this constructor 
> impacts performance, and it seems like type conversion makes it around 7 
> times slower, than direct Float usage
> 
>      @Benchmark
>      public void oldApiFloat(Blackhole blackhole) {
>          for (int i = 0; i < iterations; i++) {
>              blackhole.consume(BigDecimal.valueOf(0.1f));
>          }
>      }
> 
>      @Benchmark
>      public void newApiFloat(Blackhole blackhole) {
>          for (int i = 0; i < iterations; i++) {
>              blackhole.consume(valueOf(0.1f));
>          }
>      }
> 
>      public static BigDecimal valueOf(float val) {
>          return new BigDecimal(Float.toString(val));
>      }
> 
> 
>      Benchmark                                     (iterations) Mode 
>   Cnt    Score           Error  Units
> BigDecimalBenchmark.newApiFloat          1000  thrpt   25  28355,359 ± 
> 502,195  ops/s
> BigDecimalBenchmark.newApiFloat          2000  thrpt   25  14132,275 ± 
> 206,593  ops/s
> BigDecimalBenchmark.newApiFloat          5000  thrpt   25   5667,007 ± 
>   71,941  ops/s
> BigDecimalBenchmark.newApiFloat         10000  thrpt   25   2808,114 ± 
>   32,403  ops/s
> BigDecimalBenchmark.newApiFloat        100000  thrpt   25    278,405 ±   
> 4,642  ops/s
> BigDecimalBenchmark.oldApiFloat          1000  thrpt   25   3559,235 ± 
>   40,931  ops/s
> BigDecimalBenchmark.oldApiFloat          2000  thrpt   25   1782,190 ± 
>   21,805  ops/s
> BigDecimalBenchmark.oldApiFloat          5000  thrpt   25    712,045 ±   
> 6,495  ops/s
> BigDecimalBenchmark.oldApiFloat         10000  thrpt   25    355,959 ±   
> 6,006  ops/s
> BigDecimalBenchmark.oldApiFloat        100000  thrpt   25     36,239 ±   
> 0,423  ops/s
> 
> pt., 24 sty 2025 o 00:59 Joseph D. Darcy <joe.darcy at oracle.com 
> <mailto:joe.darcy at oracle.com>> napisał(a):
> 
>     __
>     On 1/23/2025 2:35 PM, Remi Forax wrote:
>>     Hello Jan,
>>     what you are suggesting is not a backward compatible change.
> 
> 
>     There is a source compatibility impact, meaning that for some call
>     sites, the mapping of existing code using BigDecimal before and
>     after the addition of the overloaded method would change. That
>     wouldn't necessarily preclude us from making such a change (and such
>     changes have been made in the past), but extra caution and analysis
>     would be called for.
> 
>     Cheers,
> 
>     -Joe
> 
> 
>>
>>     If we add BigDecimal,valueOf(float), then a program recompiled
>>     with the new JDK may change its behavior,
>>     you can think that the new behavior is more "correct" that the
>>     current one, but changing the behavior of existing programs is
>>     usually a big NO ! in Java.
>>
>>     Also, I believe that the reason there is no such factory method
>>     that takes a float is that doing computations on floats is not
>>     recommanded, it becomes a mess rapidly of the imprecision of the
>>     float32 representation, .
>>     For the same reason, in Java, 2.0 is a double and there is no
>>     FloatStream while there is a DoubleStream.
>>
>>     regards,
>>     Rémi
>>
>>     ------------------------------------------------------------------------
> 



More information about the core-libs-dev mailing list