-1

Is there a way in Kotlin, or Java to parse Double to Int knowing that all the doubles will not exceed the Int memory limit? examples:

Double Int
1,123 1123
1,1 11
1,12345 11234
0,12345 1234

I know we can parse it to string first and remove the '.' and then to Int but I want a more effective way.

  • 3
    Why are 5s disappearing? – g00se Aug 01 '23 at 17:58
  • 4
    What do you mean by "int memory limit"? Also this is not parsing, it is a type conversion but also the number is being transformed. 1.1 is not equal to 11. Explain the transformation expected. – aled Aug 01 '23 at 18:10
  • Technically, you have no way to achieve this other than using converting input to `String` and using regular expression [See this answer for Java](https://stackoverflow.com/a/54111864/2453382). As @aled pointed out, you are not parsing, you are `extracting`, left hand side does not correlate to right hand side of your table mathematically. –  Aug 01 '23 at 18:17
  • 1
    Please note that there is no exact value of 1.1 in `double` type. More info [Is floating point math broken?](https://stackoverflow.com/q/588004), https://floating-point-gui.de/, https://floating-point-gui.de/basic/, https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html – Pshemo Aug 01 '23 at 18:17
  • 1
    It is not reallyw clear, what conversion do you mean. Should we convert `1.1001` to `11001` or just `11`? Also, does that mean `1.1` and `1.11`, even if they are almost the same number, should be converted to much different `11` and `111`? Also, `11.1` and `1.11` should convert to exactly the same int? – broot Aug 01 '23 at 18:38
  • interesting fact: `1.1` is actually not exactly representable by `double`, the nearest double would be `1.100000000000000088817841970012523233890533447265625` – user16320675 Aug 01 '23 at 19:05
  • @user16320675 that's why BigDecimal should be used. It can avoid representation errors and has conversion methods that also prevent them in the conversion itself. See my answer. – aled Aug 01 '23 at 19:07

3 Answers3

0

Assuming that you want to keep all the significant digits you should use BigDecimal to do the conversion and transformation without missing information:

import java.math.BigDecimal;

public class MyClass {
    public static void main(String args[]) {
      BigDecimal x=BigDecimal.valueOf(1.12345);
      int y=x.unscaledValue().intValueExact();
      System.out.println("y = " + y);
    }
}

Output:

y = 112345

valueOf() is needed to create a BigDecimal from a floating point type without representation errors. intValueExact() will throw an exception if the result is out of range for an int.

Note that this solution keeps the 5 at the end of the number unlike your example.

aled
  • 21,330
  • 3
  • 27
  • 34
  • You are right. I could replace `x.movePointRight(x.scale())` by `x.unscaledValue()` and get the same result. I will do that for clarity. Thanks for pointing it out. – aled Aug 01 '23 at 19:09
0

If you know how many digits you want to keep after the decimal part you could just multiply by 10^n and store the result in an int.

The way a double is stored with a floating point is always an approximation of a number. Like others said, this means 1.1 can't be represented exactly and the real value is closer to 1.100000000000000088817841970012523233890533447265625

If we knew what you're trying to achieve with this kind of data transformation perhaps we could offer a different alternative? Because this is a very strange thing to do and I can't think of a reason why you would need to do this in any application.

0

BigDecimal is definitely the way to go here but, if you want another alternative you could do something like this....

  • Convert the double type value to string;
  • Remove the decimal point (whatever type it is);
  • Convert the string to a long data type;
  • See if the long value is greater than or equal to Integer.MIN_VALUE or, less than or equal to Integer.MAX_VALUE. If it is, convert the long value to an int. If it isn't then remove a single trailing digit from the long value and check again. Keep checking until the long value falls within the Integer.MIN_VALUE and Integer.MAX_VALUE range.

Here is a code example. Be sure to read the comments:

/* Double type values to convert in double type array. 
   You could potentially supply signed values as well.
   The decimal point identifier can be whatever suits 
   your specific system locale (. or ,):    */
double[] dblArray = {1.1234567896543217d, 1.123d, 1.1d, 
    1.1001, -1.10017887643456776d, 1.12345d, 0.12345d, 
    87.543276d, 4657.439802};

/* Display a table header in Console for the conversion results 
   from the double type array to int values. The String.format()
   method is used:        */
System.out.println("Remove decimal point and convert to int:\n");
System.out.println(String.format("%-25s %-12s", "Double (double)", "Integer (int)"));
System.out.println("=======================================");

/* Convert each double type element within the dblArray[] array
   to int ans display the results in a Table style format:   */
boolean greaterThanMinMaxInt;   // Flag
for (Double dbl : dblArray) {
    greaterThanMinMaxInt = false; // Used only for display purposes.
    /* First convert the double type data to an long type value
       by converting the double type value to String then removing 
       the decimal point (be it '.' or ',') then using the known 
       Long.parseLong() method to convert the new string value to 
       a long data type. This is done to ensure the the double 
       value conversion will fit and we can then check for Integer
       MIN/MAX.             */
    long lng = Long.parseLong(String.valueOf(dbl).replaceAll("[.,]", ""));

    /* Is the long type value less than Integer.MIN_VALUE or greater 
       than Integer.MAX_VALUE. If it is then remove a digit from the 
       trailing end of the long type value. Keep doing this until the 
       long value falls within bounds:         */
    while (lng < Integer.MIN_VALUE || lng > Integer.MAX_VALUE) {
        lng = lng / 10; // Remove last digit in long value.
        greaterThanMinMaxInt = true; // Flag set - Value needed reducing.
    }

    /* Now that the long type value is within Integer.MIN/MAX 
       values, convert the value to `int`:   */
    int intValue = (int) lng;

    /* Display the result within Console Table. Nested Ternary 
       Operators are used to display which values were actually 
       reduced in length to satisfy Integer.MIN_VALUE and 
       Integer.MAX_VALUE:  */
    System.out.println(String.format("%-25s %-12s", String.valueOf(dbl), 
            String.valueOf(intValue) + (greaterThanMinMaxInt ? (intValue > 0 
                    ? " ('Had' Integer.MAX_VALUE Overflow)" : " ('Had' Integer.MIN_VALUE Overflow)") 
                    : "")));
}

If you run the code above, you should see the following within the Console Window:

Remove decimal point and convert to int:

Double (double)           Integer (int)
=======================================
1.1234567896543217        1123456789 ('Had' Integer.MAX_VALUE Overflow)
1.123                     1123        
1.1                       11          
1.1001                    11001       
-1.1001788764345677       -1100178876 ('Had' Integer.MIN_VALUE Overflow)
1.12345                   112345      
0.12345                   12345       
87.543276                 87543276    
4657.439802               465743980 ('Had' Integer.MAX_VALUE Overflow)
DevilsHnd - 退職した
  • 8,739
  • 2
  • 19
  • 22