Coordinates not accurate when converting to int - java

I'm getting coordinates from Facebook to places and these sometimes have up to 12 decimals. When converting these to int (* 1E6) I'm loosing accuracy since it's shaving off some digits.
For example, the double 59.313732591172 is represented as int 59313732.
How can I keep the accuracy? Is there any way to do this on Android? Using the GeoPoint class I seem to be stuck with int.
Mike

An int will only hold whole numbers, so you're seeing the behaviour you ask for.
59.313732591172 * 1E6 = 59313732.591172
(int)59313732.591172 = 59313732
If you need to keep more digits, either keep using double, convert to a long instead of an int and multiply by a bigger number (e.g. 1E12)
This is just how casting floating-point to int/long works in any typed language. Here, it's a Java feature, and nothing specific to Android.

int is too short for some numbers (actually, for most of the numbers) since it has only 32-bits. Use long instead. See here

Related

How can I send with two bytes a float from type %8.5f over bluetooth low energy to my android app

I try to send sensor data continuously from a stm32wb55 to my own android app.
I receive two bytes from a acceleration sensor and convert those correctly on my stm32wb55 to a float with format (XX.XXXXX, float can be negative).
Now I want to send exactly this float to my own android app.
Before, I have send two bytes from type "int or uint" to my android app and tried to convert those the same way I have done already on the stm32wb55. But the values on my screen are up to 50% of cases false. So now I try to send the float value directly, so that no more conversion on my phone is needed.
EDIT: After your contributions, I have forget my poor idea to send a float to my android app. I tried again to send the two byte integers and convert those the right way on my app. Now it works how it should. I have found the solution I needed on this post:2 Chars to Short in C.
By combining the two bytes to a 16-Bit Integer, I just needed 0x00ff & for my LSB like it be used in the answer of the referenced post.
to a float with format (XX.XXXXX, float can be negative).
This is impossible.
floats are a 32-bit IEEE754 floating point number. They do not work like you (apparently) think they do.
Specifically, they are binary constructs with a mantissa system. I'll try to explain why it doesn't work like you think they do: What is 1/3, in decimal? You'll find that you can't write it in decimal no matter how many 'bits' (digits) you use. You'll never quite get it. There's always another 3 to add.
floating point works the same way, but it's in binary (base 2) and not decimal (base 10). That means there are numbers that work great in decimal (such as 1/10th which in decimal is 0.1, with perfect accuracy) but which are like 1/3 in binary: No matter how many bits you use, you'll never get it.
Here's another way to think about it: 32-bit, so, there are only 2^32 (about 4 billion) different values. In other words, of all the numbers in existence (and there is an infinite infinity of them: There are infinite numbers, and within any 2 consecutive numbers, another infinity of numbers), only at most 4 billion are blessed: 4 billion of all numbers in existence are representable by a float value. If you try to represent a number that isn't blessed with a float, then java / your CPU will just round it to the nearest blessed number and gives you no real opportunity to deal with the error (after all, how would you represent the error? It is rather unlikely to be blessed, either).
Thus, say, '12.34567'? That's not a blessed number - therefore, your float cannot possibly represent that. It'll instead be a number very close to it, and probably a number that would round to 12.34567 if you round it to 5 digits.
send exactly this float to my own android app.
So, no, you don't want to do that. You want to send 12.34567 to your android app, not the 32 bits that represent it. Unless you intend for the android side of the app to do the rounding, which you probably should. Note that I bet there are numbers that fit the 'XX.YYYYY' pattern that just do not 'work' as a float (they round such that you're off by 1). If that's a problem, don't use floats (use doubles where I doubt that you'll find an XX.YYYYY that doesn't have a blessed number such that it rounds correctly due to having more bits to work with, or use a string, or use 2 ints, or use a single int, and have an agreement that both sides know that the int 1234567 represents 12.34567).
That last one sounds like the most convenient trick for you here, but it's hard to tell as you haven't provided much detail.
Something like (but note that the float may be off by 1 or so!):
sender side:
double v = theFloat; // doubles have less error
int z = (int) (v * 100000);
sendToPhone(z);
receiver side:
int z = getFromDevice();
double v = z;
v /= 100000;
float theFloat = (float) v;
The above will end up automatically rounding off (rounding down for positive numbers and up for negative numbers) any digits after the floating point beyond the 5 you want), and can deal with numbers up to plus or minus 21473.99999. Sounds like that'll easily cover your needs.
NB: You'll have to write the 'multiply by 100000 and then convert to an int32' code for your stm32wb55, the above is how you'd write it if the stm32wb55 was programmed in java, which I would assume it isn't. The 'go to double before multiplying by 100000 is a probably irrelevant optimization, I wouldn't be too worried if you can't do that. Note that CPUs are not guaranteed to use the exact same IEEE754 representation for floats/doubles that java does, which is why you should definitely not attempt to send the value as a float/double across the bluetooth channel, but as something universally agreed upon, such as 'a 2's complement 32-bit integer value'.

Java - How to reduce float number precision? [duplicate]

This question already has answers here:
Java float 123.129456 to 123.12 without rounding
(5 answers)
How to round a number to n decimal places in Java
(39 answers)
Closed 5 years ago.
Can I reduce the precision of a float number?
In all the searching I've been doing I saw only how to reduce the precision for printing the number. I do not need to print it.
I want, for example, to convert 13.2836 to 13.28. Without even rounding it.
Is it possible?
The suggested answer from the system is not what I am looking for. It also deals with printing the value and I want to have a float.
There isn't really a way to do it, with good reason. While john16384's answer alludes to this, his answer doesn't make the problem clear... so probably you'll try it, it won't do what you want, and perhaps you still won't know why...
The problem is that while we think in decimal and expect that the decimal point is controlled by a power-of-10 exponent, typical floating point implementations (including Java float) use a power-of-2 exponent. Why does it matter?
You know that to represent 1/3 in decimal you'd say 0.3(repeating) - so if you have a limited number of decimal digits, you can't really represent 1/3. When the exponent is 2 instead of 10, you can't really represent 1/5 either, or a lot of other numbers that you could represent exactly in decimal.
As it happens .28 is one of those numbers. So you could multiply by 100, pass the result to floor, and divide by 100, but when this gets converted back to a float, the resulting value will be a little different from .28 and so, if you then check its value, you'll still see more than 2 decimal places.
The solution would be to use something like BigDecimal that can exactly represent decimal values of a given precision.
The standard warnings about doing precision arithmetic with floats applies, but you can do this:
float f = 13.2836;
f = Math.floor(f * 100) / 100;
if you need to save memory in some part of your calculation, And your numbers are smaller than 2^15/100 (range short), you can do the following.
Part of this taken from this post https://stackoverflow.com/a/25201407/7256243.
float number = 1.2345667f;
number= (short)(100*number);
number=(float)(number/100);
You only need to rememeber that the short's are 100 times larger.
Most answers went straight to how do represent floats more accurately, which is strange because you're asking:
Can I reduce the precision of a float number
Which is the exact opposite. So I'll try to answer this.
However there are several way to "reduce precision":
Reduce precision to gain performance
Reduce memory footprint
Round / floor arbitrarily
Make the number more "fuzzy"
Reduce the number of digits after the coma
I'll tackle those separately.
Reduce precision to gain performance
Just to get it out of the way: simply because you're dropping precision off of your calculations on a float, doesn't mean it'll be any faster. Quite the contrary. This answer by #john16384:
f = Math.floor(f * 100) / 100;
Only adds up computation time. If you know the number of significant digits from the result is low, don't bother removing them, just carry that information with the number:
public class Number WithSignificantDigits {
private float value;
private int significantdigits;
(implement basic operations here, but don't floor/round anywhere)
}
If you're doing this because you're worried about performance: stop it now, just use the full precision. If not, read on.
Reduce memory footprint
To actually store a number with less precision, you need to move away from float.
One such representation is using an int with a fixed point convention (i.e. the last 2 digits are past the coma).
If you're trying to save on storage space, do this. If not, read on.
Round / floor arbitrarily
To keep using float, but drop its precision, several options exist:
#john16384 proposed:
`f = Math.floor(f * 100) / 100;`
Or even
f = ((int) (f*100)) / 100.;
If the answer is this, your question is a duplicate. If not, read on.
Make the number more "fuzzy"
Since you just want to lose precision, but haven't stated how much, you could do with bitwise shifts:
float v = 0;
int bits = Float.floatToIntBits(v);
bits = bits >> 7; // Precision lost here
float truncated = Float.intBitsToFloat(bits);
Use 7 bitshifts to reduce precision to nearest 1/128th (close enough to 1/100)
Use 10 bitshifts to reduce precision to nearest 1/1024th (close enough to 1/1000)
I haven't tested performance of those, but If your read this, you did not care.
If you want to lose precision, and you don't care about formatting (numbers may stil have a large number of digits after the coma, like 0,9765625 instead of 1), do this. If you care about formatting and want a limited number of digits after the coma, read on.
Reduce the number of digits after the coma
For this you can:
Follow #Mark Adelsberger's suggestion of BigDecimals, or
Store as a String (yuk)
Because floats or doubles won't let you do this in most cases.

Using Java BigDecimal for a 15 precision digit (scale of 2)

I found a partial answer here, but I knew this already. So I decided to post a new question.
I am trying to convert a HTTP request parameter string to a 15 precision Java BigDecimal number (with scaling of 2). For example,
String x = request.getParameter("seqNo"); /* e.g. 12345678910111213141516.17181920 whatever */
// I want to convert x so that it has a precision of 15 and scale of 2 i.e. 111213141516.17.
I don't care about rounding. It's a form of reference number, so irrelevant of rounding. I know that scaling can be set by using overloaded setScale(int) method that will return a scaled(Truncated?) BigDecimal. But how to make sure that the precision is set properly?
How about using substring instead? It's not really a number anyway.
int pos = x.indexOf('.');
String y = x.substring(pos - 12, pos + 3);
If you are really crazy enough to try processing this as numbers (collissions and differences in rounding are going to break your neck sooner or later!), you could do this.
double v = Double.parseDouble(y); // REALLY REALLY REALLY NOT RECOMMENDED.
But this is a very very bad idea. Don't squeeze something into a number column that is not a number. Next week, you'll get numbers with two dots, and it will break in every possible way.
If you do not need to do mathematical computations, treating such a field as VARCHAR or TEXT is perfectly acceptable. Because that is what it is: a sequence of characters. Not a number.
In fact, I would strongly advise to store the whole number, as VARCHAR. It is a unique identifier, not a mathematical number to do computations with.

Java Math.pow issue

I am working on a program which needs to cube a number. Long story short, I need to compare the number to a string, so I need to get rid of the decimal place a double gives when I convert to string. To do this, I used Math.round and saved it as a long. This works fine for relatively normal numbers, but the numbers can go up to 999,999.
I used 275393 (a given test number, so I'm assuming it must be correct for the problem I'm working on) and neither a calculator nor the computer seemed to get the correct answer. The correct answer is supposed to contain 123457 somewhere in the results, but the calculator has 12346 (which I think is just rounding, as it stops listing numbers after this) and the computer has 123456 (the computer stops listing numbers after this point). Is rounding it giving it the problem (it shouldn't because I'm pretty sure it only rounds to the tenths place, but who knows)? Or is it something else?
Math.pow() takes two doubles and returns a double. There is not enough precision in a double to represent 2753933 = 20886164356123457 (exact).
The solution is to use BigInteger.pow().
A double has limited precision. Instead, use BigInteger or BigDecimal for your calculation.
I need to compare the number to a string, so I need to get rid of the decimal place a double gives when I convert to string.
Do it the other way around. Convert the String to a number, then compare it to the double (with a small tolerance to account for inaccurate binary representations of float point numbers).

Four questions - Calculator Application - Android Java

Hey all, I am a total newbie developing an android application, I've been reading 'Sams Teach Yourself Java in 24 hours' and it's a great book. But I have been stuck on a bit where I get the value of a decimal number only editTexts and use java maths to work out my end value.
Is there a way to have an editText input straight to a float or double variable rather than to a string and then from a string to a double?
Are there any real issues with converting between a string and a double or float or will the values remain the same and not be polluted.
Differences / pros and cons of using a doble as opposed to a float.
Best way to input a fraction value from the user?
Thanks for any help. Have a good day.
No, you can't.
Yes. If your string is, say, an ID and reads like "0029482", after you turn it into an integer it will read "29482" and probably will be invalid. Strings can be longer than doubles or floats, and if you have a value like "0.12345678901234567890123456789" in a string, you will lose a lot of precision by converting that to a double.
Doubles use double the number of bits (hence the name), and can therefore hold more precision.
Accept the denominator and numerator integers, and store them in a custom class.
No. You could write your own subclass that makes it seem like that is what's happening, but at some point somewhere in the chain you have to do a conversion from character/text data to numerical data.
Yes. Primitive floating-point types use IEEE-754 to encode decimal numbers in binary. The encoding provides very good precision, but it is not exact/cannot exactly represent many possible numbers. So if you parse from a string to a primitive floating-point type, and then back to string again, you may get something that is different from your input string.
A double uses twice as many bits to encode the number as a float, and thus is able to maintain a greater degree of precision. It will not, however, remove the issues discussed in #2. If you want to remove those issues, consider using something like BigDecimal to represent your numbers instead of primitive types like float or double.
Read the whole thing as a string, split() it on the '/' character, and then store each part as an integer (or BigInteger). If you need to display it as a decimal, use BigDecimal to perform the division.
I'd just like to add that if you are looking for an alternative to double or float that doesn't entail loss of precision when converting between strings and numeric form, look at these:
The standard java.math.BigDecimal class represents an arbitrary precision scaled number; i.e. an arbitrary precision integer multiplied (scaled) by a fixed integer power of 10.
The Apache dfp package contains implementations of decimal-based floating numbers.
However, I'd steer clear of both of this topic for now, and implement using float or double. (I take it that your real aim is to learn how to write Java, not to build the world's greatest calculator app.)

Categories