DoubleValue of BigDecimal provided wrong output - java

Using java 11 and Intellij Idea.
I'm in the situation where I get a string of data from an external system and need to reformat this. In the current setup I have this line to extract the value for a sales price:
BigDecimal sellingPrice = BigDecimal.valueOf(Double.parseDouble(somesalesprice));
According to the debugger, the output value of sellingPrice = "4.350000000"
Now when I convert this according to this line of code:
long roundedSellingPrice = (long) (sellingPrice.doubleValue() * 100);
the result turns out to be "434". As can be seen, 1 (cent) has magically disappeared. I double-checked the values and this consistent. Out of the 500+ dataset that I'm working with, approx. 40 other records seem to have this problem. For the majority it seems to be going just fine.
I cannot find anything common between these records.
Also, it turns out, the result is always rounded down by 1 cent, never up.
Wonder what this could be?

As weird as it sounds for the data of types Float and Double the precision is not very good. Use BigDecimal for all the calculations. That's the short answer.
In Addition, when you parse a String to any numerical type you have to deal with exceptions. Sometimes it makes sense and sometimes it doesn't. For the case when you don't care about exception I wrote a utility that parses string to any numeric value and if parsing fails it returns a default value. In case you want your exception messages to be printed into log the same utility optionally may print exception messages into a log. See methods:
public static java.math.BigDecimalparseStringToBigDecimal(java.lang.CharSequence num, java.math.BigDecimal defaultValue) and
public static java.math.BigDecimal parseStringToBigDecimal(java.lang.CharSequence num,
java.math.BigDecimal defaultValue,
java.lang.String nullOrEmptyStringErrorMessage,
java.lang.String numberFormatErrorMessage)
Those methods can be pretty useful. The utility is comes with Open Source MgntUtils library written and maintained by me. You can get it as maven artifacts or at Github

Related

NumberFormatException error on returning largest number?

I'm practicing Java online and one of the practice problems is to:
"Write a method called largerAbsVal that takes two integers as parameters and returns the larger of the two absolute values. A call of largerAbsVal(11, 2) would return 11, and a call of largerAbsVal(4, -5) would return 5."
I have already wrote my method solution which so far is:
public static int largerAbsVal(int a, int b) {
return Math.max(Math.abs(a), Math.abs(b));
}
But for some reason, the website keeps telling me that my code caused an error of type NumberFormatException? I already declared the two parameters as integers at the heading so what exactly is wrong with my code in this case?
Any help is greatly appreciated!
From NumberFormatExecpton:
Thrown to indicate that the application has attempted to convert a string to one of the numeric types, but that the string does not have the appropriate format.
The code you posted works great! My guess is your error is somewhere before that piece of code where you're converting a string to an int. Example:
Integer.parseInt(string)
And that the string given is malformed (i.e. not an int). For example, something like "2.1" will throw an error like this.
Hope this helps!

How to distinguish long and double-values when deserializing with moshi?

My goal is to synchronize abitrary rows of data by using the JSON-Format.
As I do not know the exact scheme for the rows (it is a general sync method), my datamodel apparently has to rely on "Object". So in Java I will have an array of Map<String,Object> to be synchronized with the server.
Translating such a row into JSON would give something like
{{"string":"stringvalue"},{"double1":1234.567},{"double2":1234.0},{"long":1234}}
so far, so good - no problem with moshi - everything works as expected.
Now the Problem: When I try to deserialize that JSON with moshi, I get back a double-value for the "long" member. Moshi converts all numbers to Doubles. But unfortunately not all numbers can be safely converted to doubles. Very big integers (aka longs) have a problem with the limited precision of doubles. And rounding-effects also might exist.
I opened an issue with moshi, but unfortunately that was closed. Maybe I wasn't clear enough. (Issue 192)
JSON has no concept of integer - only numbers and Strings. But the subtle detail from "double2" from the example above might lead to a solution for my problem:
If a number does not contain a decimal-point, it is an integer and should be converted to a long.
As longs can not be losslessly converted to doubles, I need a method to intercept the parser before the value is converted to double. But how to do that?
Moshi has this handy concept of JsonAdapters - but unfortunately I currently do not see how I can use them in this case:
The input-type of such an JsonAdapter would have to be Object because I can not cast a generated double to long. So I have to intercept the parser before he converts any value.
But how to return more than one type from there? (I would have to return String, Double or Long from there - or if I can limit the inputs to only numbers I would at least have to return Longs or Doubles.)
(My backend is written in PHP and automatically produces the desired output: Integers are written without a decimal-point.)
I am afraid it's not possible without changing Moshi source code. The JSON string source passes through JsonReader which converts all numbers to double. I could not find a way how to alter this behavior since all subclasses are package-protected.

Changing Doubles To Ints

Im working on a homework assignment for my intro to computer science class and we are are inputting basic commands to get the percentage of people who drink a certain kind of energy drink. We used JOptionPane to make text boxes and you can input the amount of people and the computer has a set percentage to get the output. My problem is i set up my variables as doubles and my answers are very long decimals. I want to convert the answers to Ints so i can get whole numbers. I have tried to do this through casting but i keep getting the error message" EnergyDrink.java:14: error: variable citrusEnergyDrinkers might not have been initialized". What can i do?
This can't be solved without code. The error is not due to any problem with the conversion, but simply as the compiler-error says:
variable citrusEnergyDrinkers might not have been initialized
This means that the variable might not hold a value at the time you attempt to convert it, which results in undefined behaviour, which java-designers didn't allow for a reason.
The problem is as the error-message tells: citrusEnergyDrinkers gets its value inside some try-catch-block or a block that is only run under certain conditions, like if. One way to work around this would be to simply initialize citrusEnergyDrinkers as 0:
double citrusEnergyDrinkers = 0;.
Note though that this might produce incorrect results depending upon what happens when the value isn't set in case the above mentioned block of code isn't entered/breaks off before setting a value.
For the conversion:
Math.round(citrusEnergyDrinkers) is most likely preferable to a simple cast to int, since double most of the time has some imprecision due to the way it's stored in memory and round will actually round the value, while a cast will simply remove the frictional part. For example:
(int) 0.75 //produces 0
Math.round(0.75) //produces 1
You could multiply the double by 100 and then cast to an int:
double d = .77583495;
int perc = (int) Math.round( d );
I prefer to not cast like that, but it works.
Good luck.

Disable Java making big number smaller? (10,000,000,000 to 1E10)

I have a big number in a database; in this case, 10,000,000,000. Whenever I use that information for something, like sending a message with it, instead of 10,000,000,000, it says 1E10, and I really do not want that.
Can I avoid that in any way?
If I go to the database, the value is 10,000,000,000.
It's the same number, just represented in scientific notation.
Since you don't describe how you are storing the value, you can use DecimalFormat#getNumberInstance to help format it to one that doesn't contain the scientific notation.
double foo = 10000000000L;
System.out.println(foo);
System.out.println(DecimalFormat.getIntegerInstance().format(foo));
This outputs:
1.0E10
10,000,000,000

why do i have to use Integer.parseInt?

I am new to Java so forgive me if this is a silly question.
First I did the following (this is a section from my code):
public static void team()
{
int score = JOptionPane.showInputDialog("Enter the team score...");
calculate(score);
}
But I kept getting an error saying: "Incompatible types string cannot be converted to int".
So I thought I may need to use parsing. I did the following and it worked:
public static void team()
{
int myScore;
String score = JOptionPane.showInputDialog("Enter the team score...");
myScore = Integer.parseInt(score);
calculate(myScore);
}
I would like to know why there is a need for me to parse the variable "score"? In the first piece of code, I declared the variable score as an integer, so would it not store the input which I expect to be an Integer in the variable score which is then passed into the method calculate. I understand that parsing is when you convert a String into an Integer. However in this case, I do not expect the user to input a string so why is there a need for parsing?
The simple reason is: because JOptionPane.showInputDialog() returns a String, regardless of what you actually want the user to input.
There's no mechanism in Java to do automatic conversion based on the type of your destination variable myScore (though some other languages can do this, e.g. implicit conversions in Scala).
You could (in principle) create a custom dialog that returns an int , e.g. by getting the user to choose from a pulldown list of numbers, and then no parsing would be needed. But otherwise, you have to do parsing explicitly.
The JOptionPane.showInputDialog("Enter the team score..."); returns a String which you tried to store in a int. That is why you are getting the "incompatible types".
See Javadocs for more information.
Because a string is stored differently than an integer. Integers are stored in binary, while as a String is a collection of characters.
Example:
The number 14 would be stored as 1110 in Binary. However, as a String, it's stored as 00110001 00110100
Take a look at this http://www.roubaixinteractive.com/PlayGround/Binary_Conversion/The_Characters.asp
Integer.parseInt() basically does the dirty work for you, by looking up the characters in a lookup table, and as long as they correlate with proper integer values, it coverts it over to binary form, to be stored in an integer.

Categories

Resources