storing double values in SQLite: how to ensure precision? - android

i have a problem with double values i need to store in an android homed sqlite database. since these double values represent gps values (lat & lng), i really NEED an absolute precision down to the 9th number after the comma.
now i have a table like this:
CREATE TABLE x REAL lng;
and insert sth (hardcoded) like:
INSERT INTO x lng = '1.0';
and when reading lng from this table into some (java) double variable, i get a value like "0.999956837" - this renders the values pretty useless to me.
is there a way to enforce the precision i need other than storing the values as "text" fields (what would make expensive casts neccessary) or storing them as integers (meaning i need to multiply/divide at each write/read-op)?

SQLite is typeless, that means all representation is written as text, probably the wrapper api does some converts you don't know of, that you get those results.
If you need to store the data as string do it.
Just when you read out the double make sure you saved in the right format, you can use getDouble on the column.

double has about 17 decimal digits of precision, so if 9 digits is what you need, there should be no problem (assuming that you don't do any complex calculations on those values). Just make sure you never end up using float, because that has only about 7 digits of precision.
You should also make sure you understand how binary floating-point works, and that it will always result in seemingly "round" values becoming slightly off - which simply does not matter for most applications (including yours) as long as it happes somewhere in the 17th decimal digit. See that link also for alternatives for applications where it does matter.

Related

fromjson fails to parse scientific notation - Android [duplicate]

I can easily read 2e15 as "two quadrillion" at a glance, but for 2000000000000000 I have to count the zeroes, which takes longer and can lead to errors.
Why can't I declare an int or long using a literal such as 2e9 or 1.3e6? I understand that a negative power of 10, such as 2e-3, or a power of 10 that is less than the number of decimal places, such as 1.0003e3, would produce a floating point number, but why doesn't Java allow such declarations, and simply truncate the floating-point part and issue a mild warning in cases where the resulting value is non-integral?
Is there a technical reason why this is a bad idea, or is this all about type-safety? Wouldn't it be trivial for the compiler to simply parse a statement like
long x = 2e12 as long x = 2000000000000 //OK for long
and int y = 2.1234e3 as int y = 2123.4 //warning: loss of precision
It's because when you use the scientific notation you create a floating point number (a double in your example). And you can't assign a floating point to an integer (that would be a narrowing primitive conversion, which is not a valid assignment conversion).
So this would not work either for example:
int y = 2d; //can't convert double to int
You have a few options:
explicitly cast the floating point to an integer: int y = (int) 2e6;
with Java 7+ use a thousand separator: int y = 2_000_000;
Because it's a shortcoming of Java.
(Specifically, there is clearly a set of literals represented by scientific notation that are exactly represented by ints and longs, and it is reasonable to desire a way to express those literals as ints and longs. But, in Java there isn't a way to do that because all scientific notation literals are necessarily floats because of Java's language definition.)
You are asking about the rules on writing a integer literals. See this reference:
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
The capability to use scientific notation as an integer literal might make things easier indeed but has not been implemented. I do not see any technical reason that would prevent such a feature from being implemented.

How to store currency values in Realtime Database

I have the following data. To me both are Double type. But Firebase always takes 69.0 as 69. Then I can't declare the property price as Double because I'm getting the exception:
firebase.database.DatabaseException: Failed to convert value of type
java.lang.Long to Double
Is there a way to force a Double type to a specific property?
If you're going to store money values in a database, consider that floating point numbers can be inaccurate, due to the way they're represented according to the IEEE 754 specification. A full discussion of this is too long to put here.
You can work around this by multiplying all your prices values by some value that eliminates the fractional part of the number and only stores integers. With US dollars, for example, there is no smaller unit of currency than 1 cent. Instead of storing floating point value .01 to represent this (possibly losing precision), I could multiply it by 100 and store an integer 1, without losing any precision.
If I eliminate floating point numbers from my prices like this, now I'm only storing integer values. After reading them on the client, I still have to format them as dollars and cents, which means I have to write some extra code to format prices values like "399" into "$3.99", which is not that difficult, and I can do it without losing any precision.
If you're storing currency values other than US dollars, you may have a different scheme, but the idea is the same - convert your fractional prices into integers for storage in the database, then format those values as the user would expect to see them.

3 Android GPS Questions

1) For some reason, the longitude and latitude are slightly different after storing them. For example, when i first find them, they are:
25.171057657111998 and 35.013447496224636 but after I store them , they are
25.1710586547852 and 35.0134468078613. Why is this happening? I store them as floats in an sqlite database, retrieve them with Cursor.getFloat, and print them with String.format of 13 digit accuracy.Can this difference affect the end results in a significant way? I am working with distances <100m (328 feet)
2)I am trying to find the center of a location cluster. Here
http://www.geomidpoint.com/calculation.html
method C says I can just take a simple average if I work with <400km. Has anyone tried it? Is it working? Or should I go for the first, more accurate method?
3) After finding the center, do I need anything else to create a new location object for distance purposes?
To solve this problem you may store longitude and latitude in your sqlite database by this way:
longitude*10^10 , latitude*10^10
when you get them you will divide them by 10^10.
because with 5 decimal is accurate

Android: BigDecimal to Float loss of data

I store a variable in sqlite db as REAL but in my app I need to use it as BigDecimal.
The problem is, I am not able to save my BigDecimal variable to my sqlite without converting it to float or double.
so I do the following:
bigDecimal.floatValue();
but by doing that a loss of precision occurs.
for example
if I put to my editText from which I get the variable: 123456789
after converting it from bigDecimal to float I get : 123456792
The same happens if I try to cast bigdecimal to string:
String.valueOf(bigDecimal);
the problem occurs ONLY if the variable which I put is at least 8 digits long.
It behaves the same way if its a decimal number and the numbers differ always after the seven digit.
is that a normal behaviour ? how to avoid it?

Math.sin() does not give accurate results [I'm using Math.toRadians to pass the right values]

I'm actually using Math.sin() in my android app to calculate a sinus of a given angle (using Math.toRadians(angle_in_degrees)). For exemple when I want to get the Math.cos(90) which is 0, the result is 6.123233... E-17. Thanks you.
For floating point numbers, the system can often only approximate their values. For instance, the system would return something like 0.333333 for the expression (1.0 / 3). The number of 3s after the decimal point will be different depending on whether you're a floats or doubles, but it will still be limited to some finite length.
If you're just displaying the value, then you can limit the number of digits using something like String.format("%0.2f", value) or by rounding it using one of the rounding functions such as Math.round().
The tricky part comes when you need to compare the value to something. You can't just use if (value == some_constant) or even if (value == some_variable). At minimum, you usually have to use something like if (Math.abs(value - some_constant) < 0.001). The actual value of the '0.001' depends on the needs of your particular application and is customarily defined as a named constant.
For more complicated needs, you can implement the algorithm in the Floating-Point Guide.
You're getting back an approximation from Math.cos(Math.toRadians(90)) which is
6.123233... E-17 == 0.00000000000000006123233... which is basically 0
The following link should help clear things up as far as the precision of doubles/floats in programming.
http://www.java67.com/2015/09/float-and-double-value-comparison-in-java-use-relational.html

Categories

Resources