Search code examples
javafloating-pointbigdecimal

Calculating double neighbours of a decimal value


The code:

import java.math.*; 

public class x
{
  public static void main(String[] args)
  {
    BigDecimal a = new BigDecimal(0.1);
    BigDecimal b = new BigDecimal(0.7);
    System.out.println(a);
    System.out.println(b);
  }
}

The output:

0.1000000000000000055511151231257827021181583404541015625 0.6999999999999999555910790149937383830547332763671875

This is nice because it lets me find a double that is the closest to given value. But as for 0.1 a value is bigger and for 0.7 value is smaller than real value.

How can I get both values (closest bigger and closest smaller) for any decimal number?

Assume I start with BigDecimal, then convert it do a double and then back to decimal. I'll get bigger or smaller value. How could I got the other?


Solution

  • Use nextAfter(double start, double direction):

    import java.math.*;
    
    public class a
    {
      public static void printNeighbours(BigDecimal start)
      {
        double result1 = start.doubleValue();
        double result2;
    
        BigDecimal r1 = new BigDecimal(result1);
    
        int com = start.compareTo(r1);
    
        if(com != 0)
          result2 = Math.nextAfter(result1, com * Double.MAX_VALUE);
        else
        {
          result2 = Math.nextAfter(result1, Double.MAX_VALUE);
          result1 = Math.nextAfter(result1, -Double.MAX_VALUE);
          r1 = new BigDecimal(result1);
        }
    
        BigDecimal r2 = new BigDecimal(result2);
    
        System.out.println("starting:\t"+start);
    
        if(com<0)
        {
          System.out.println("smaller:\t" + r2);        
          System.out.println("bigger:\t\t"+r1);
        }
        else
        {
          System.out.println("smaller:\t" + r1);        
          System.out.println("bigger:\t\t"+r2);
        }
    
        System.out.println();
      }
    
      public static void main(String[] args)
      {
        printNeighbours(new BigDecimal("0.25"));
        printNeighbours(new BigDecimal("0.1"));
        printNeighbours(new BigDecimal("0.7"));
      }
    }
    

    Printout:

    starting:   0.25
    smaller:    0.2499999999999999722444243843710864894092082977294921875
    bigger:     0.250000000000000055511151231257827021181583404541015625
    
    starting:   0.1
    smaller:    0.09999999999999999167332731531132594682276248931884765625
    bigger:     0.1000000000000000055511151231257827021181583404541015625
    
    starting:   0.7
    smaller:    0.6999999999999999555910790149937383830547332763671875
    bigger:     0.70000000000000006661338147750939242541790008544921875