Precision of double lost when reading from Jackson - java

This should be a simple issue but I just couldn't find anything on the Internet.
Here is the JSON string
{"ratio":2.714,"daily":161.0,"userId":811032853,"topic":"#GOP2012","gender":"Unknow"}
Then when I do mapper.readValue(*theString*,*theClass.class*), all the numbers after the decimal point are lost. For the example above, I just got 2.0 for ratio.
The version of jackson I'm using is 1.9.9, which should be the latest version.
Does this happen to anyone else as well? Thanks everyone :)
The theClass is just a class that holds all these variables. The type of ratio is double.

I would suspect something odd with class definition. Jackson does not truncate double values, beyond the usual caveats with binary floating point notations (i.e. if you wanted to avoid any rounding errors, you should use BigDecimal etc), which are not enough to cause problems like this.
So it would be useful to see definition of theClass. If truncation does occur the way explained, it would definitely be a bug.

I have not worked with JackSon, but can you somehow try something like this....
DecimalFormat df = new DecimalFormat("#.###");
df.format(doubleValue);

Related

How do I format a JSR-385 Quantity with fixed number of decimal digits?

I'm trying to convert hard-coded formatting to a Java Units API implementation.
The existing code outputs (for this example, the temperature value in degrees) with two decimal places. For example, 38.70°C. While I'd like to allow the user to specify their own formatting code (which is the end-goal of the change), I think it would be useful to keep the legacy behavior to give people a chance to migrate.
The existing code looks like:
return String.format("%.2f\u00B0C", this.temperature);
The code I'm trying to use looks like:
DecimalFormat numberFormat = (DecimalFormat) DecimalFormat.getInstance();
numberFormat.setMinimumFractionDigits(2);
numberFormat.setMaximumFractionDigits(2);
NumberDelimiterQuantityFormat formatter =
NumberDelimiterQuantityFormat.builder()
.setNumberFormat(numberFormat)
.setDelimiter("")
.setUnitFormat(SimpleUnitFormat.getInstance())
.build();
return formatter.format(temperature);
It does format, but not with the specified precision. I'd expect 38.70°C but instead get 38.70000076293945℃.
If I just do
numberFormat.format(temperature.getValue().floatValue());
then it does format correctly ("38.70"). So I think the DecimalFormat is basically OK.
I considered just manually building my formatting. However that doesn't really work for what I want to do - pass in the NumberDelimiterQuantityFormat (or applicable interface).
Can anyone suggest an appropriate way to format a Quantity<> with fixed decimal precision?
First off, I'm completely unfamiliar with the Java Unit API and this implementation, but this seemed like an interesting question, so I looked into it.
I had a look at the implementation of NumberDelimiterQuantityFormat and right there in the implementation of the format method it modifies the maxiumFractionDigits of the NumberFormat depending on the fraction
if (quantity != null && quantity.getValue() != null) {
fract = getFractionDigitsCount(quantity.getValue().doubleValue());
}
if (fract > 1) {
numberFormat.setMaximumFractionDigits(fract + 1);
}
Source
This makes little sense to me for two reasons:
It negates the whole reason to have a NumberFormat in the first place especially in context with floating point numbers where it's virtually impossible to avoid superfluous fraction digits.
It modifies the internal state of the NumberDelimiterQuantityFormat in a method where it isn't expected.
I should have checked first, but there is actually an issue about this, which is "being analyzed" for several months now. Maybe it would make sense to ask in there.

How can I convert something to double?

I have an object from an implemented class ReportManager. Now getReport() is a number like 0.23 with the data type report. But I want this number to be a double so I can work with it.
I cannot change the class, because it is implemented in the Java compiler (it is for writing macros for a program).
Does anybody have a suggestion how I could handle it? I checked the API and there is no function implemented that could help me.
EDIT: I do have the situation: I want to calculate the Center of Pressure of an object in my simulation. So I need the moment in that position to be 0.
Now: This is how the automated macro ask the value of the Moment:
MomentReport momentReport_0 =
((MomentReport) simulation_0.getReportManager().getReport("Moment 1"));
Now I want to take the abs of it, because I don't mind if it's positive or negative.
while(Math.abs(momentReport_0) > 0.2)
(Do iterate and change position.) At the end I want to println the the position.
simulation_0 is an object of Simulation. I could copy a part of the API if it's needed. Just don't know which class documentation would help.
You can cast the number to a double so that you can work with it, assuming it's returning you a single-precision float at the moment.
double result = (double) reportManager.getReport();
I recommend you read up on what typecasting is so that you can better understand what's going on here, as there would be some situations where it's unsafe to cast:
https://en.wikipedia.org/wiki/Type_conversion

DecimalFormat weird behavior with pattern #####0.00 in Java

I am using below code snap to display float price value with two decimal points.
NumberFormat FORMAT = new DecimalFormat("#####0.00");
float myFloatValue =\\I am able to fetch this value dynamically
String finalPrice = FORMAT.format(myFloatValue);
// I am using this String (finalPrice) for export xml purpose.
It seems working fine normally, but I have noticed some examples(given below) where it is not working properly and produce the price with more than two decimal points. I am not able to replicate it again, I can see it in only log files.
Some examples output of finalPrice String : 0.10999966, 0.1800003, 0.45999908.
Can anybody help me to guess original value of myFloatValue from these outputs? So that it will help me to replicate the scenario and fix it.
The sporadic occurrence makes me wonder whether the DECIMAL_FORMAT is used in several threads concurrently. That is a no-no. However one would expect
wrong values too.
Maybe for good order also specify a fixed Locale (decimal point vs. comma, thousand separators).
And finally float or even double are not suited for financial software: those numbers are approximations.
BigDecimal price = new BigDecimal("9.99");
price = price.multiply(BigDecimal.TWO); // 19.98 exact
BigDecimal is a PITA for writing calculations, but keeps its precision.

BigDecimal precision above 1E22

for some reason I found myself coding some piece of software, that should be able to perfom some astronomic calculations.
While most of it will be about transfering the correct formula into Java, I found an annoying Problem right at the verry beginning of my "test how to calculate big numbers".
Well... Imagine the Sun (our Sun), which has a mass of (about and rounded, for more easy explaining) 10E30 kg. Ten with 30 following Zeros. All native datatypes are just unusuable for this. To mention: I KNOW that I could use 3000 to calculate things and just add trailing zeros in the output-view, but I hoped to keep it as precise as possible. So using short numbers will be my last resort only.
Comming to the Problem. Please have a look at the code:
BigDecimal combinedMass = new BigDecimal(1E22);
int massDistribution = 10;
Integer mD1 = massDistribution;
Integer mD2 = 100 - massDistribution;
BigDecimal starMass;
BigDecimal systemMass;
systemMass = combinedMass.divide(new BigDecimal("100")).multiply(new BigDecimal(mD1.toString()));
starMass = combinedMass.divide(new BigDecimal("100")).multiply(new BigDecimal(mD2.toString()));
System.out.println((systemMass).toEngineeringString());
System.out.println((starMass));
It will output 1000000000000000000000 and 9000000000000000000000, whats exactly what I did expect. But look at the combineMass Field. If I raise it to 1E23, the Output will change
I get 9999999999999999161139.20 and 89999999999999992450252.80...
So I know I could use jut BigInteger, because its more reliable in this case, but for the sake of precicion, sometimes the BigWhatEver may drop to something like 50.1258
Plus, I hope to get the 10.xE30 as output, whats only possible using bigDecimals.
I want to know: Is there no way avoidng this (that error appers above 1E23 for every value I tried), while keeping the ability to calculate Floating-Points? Should I cut the After-Decimal-Separator-Values for this Field to two digets?
And for something more to wonder about:
System.out.println(combinedMass.precision());
in relation with the code above will provide 23 for that case, but En+1 for most other values (Thats was when I grow really confused)
Thanks for advise.
You're using basic types without realizing it:
new BigDecimal(1E22);
Here, 1E22 is a primitive double, and you already lost precision by using it.
What you want is
new BigDecimal("10000000000000000000000");
or
new BigDecimal(10).pow(22);

BigDecimal rounding not rounding

I'm very new to android programming so any help would really be appreciated.I have gone through the pages and do not seem to find the right answer. If this is a similar question I honestly do apologize.
My problem is that when I wrote the code on my android device with AIDE compiler the rounding of example below
pitch_round.setScale(2,BigDecimal.ROUND_UP);
worked fine and I was able to output the rounded bigdecimal to a TextView by using pitch_round.ToString() , when I used similar code in Eclipse there wasn't an error in compiling but the ouput to textview did not seem to round at all , if i am not mistaken there seems to be more decimal characters now.
Below is a snippet of the code that is not working.Is there something that I am not doing right here? All falues are floats
This is identical to the code that was used on AIDE on the device
Thank you in advance
pitch = mOrientation[1]*57.2957795f;
roll= mOrientation[2]*57.2957795f;
yaw= mOrientation[0]*57.2957795f;
// change to bigdecimal object
BigDecimal pitch_round = new BigDecimal(pitch-zero_pitch);
BigDecimal roll_round = new BigDecimal(roll-zero_roll);
BigDecimal yaw_round = new BigDecimal(yaw-zero_yaw);
pitch_round.setScale(2,BigDecimal.ROUND_UP);
roll_round.setScale(2,BigDecimal.ROUND_UP);
yaw_round.setScale(2,BigDecimal.ROUND_UP);
Log.i(SENSOR_SERVICE, pitch_round.toString());
t_pitch.setTextColor(Color.CYAN);
t_roll.setTextColor(Color.CYAN);
t_yaw.setTextColor(Color.CYAN);
// log some output to test code
//Log.i(SENSOR_SERVICE, "Send Results"+ pitch);
t_pitch.setText(pitch_round.toString());
t_roll.setText(roll_round.toString());
t_yaw.setText(yaw_round.toString());
Change all like
pitch_round.setScale(2,BigDecimal.ROUND_UP);
to
pitch_round = pitch_round.setScale(2,BigDecimal.ROUND_UP);
BigDecimal is immutable, calls of this method do not result in the original object being modified
setScale returns a new BigDecimal, which you're discarding. Try
pitch_round = pitch_round.setScale(2,BigDecimal.ROUND_UP);
From the setScale API doc:
Note that since BigDecimal objects are immutable, calls of this method
do not result in the original object being modified, contrary to the
usual convention of having methods named setX mutate field X. Instead,
setScale returns an object with the proper scale; the returned object
may or may not be newly allocated.

Categories