Float Value being Truncated in RoR 3.2 - ruby-on-rails

When saving my longtitude and latitude in my Rails 3.2 app, the value's getting truncated on save.
I've tried in the console and it's saving the full value:
item.update_attributes(:latitude => '51.07763839854951')
item.latitude:
=> 51.07763839854951
Saving the same value in the browser gives me an output of:
51.0865174
What can I do to prevent this?

The value is probably being truncated when it is stored in the DB. Regardless of the exact cause, if this value is precise and needs to be stored and retrieved losslessly, a floating-point number is probably the wrong data type to use. Floating point numbers can lose precision when you perform certain arithmetic operations on them, so they are not appropriate for values which must be exact.
When you are defining your DB schema using Rails migrations, you can use the :decimal type for decimal values which must be stored precisely. (When ActiveRecord pulls these values out of the DB, they will become BigDecimal objects rather than Floats You can do arithmetic on BigDecimals without losing precision.)

Related

Delphi - comparison of two "Real" number variables

I have problem with comparison of two variables of "Real" type. One is a result of mathematical operation, stored in a dataset, second one is a value of an edit field in a form, converted by StrToFloat and stored to "Real" variable. The problem is this:
As you can see, the program is trying to tell me, that 121,97 is not equal to 121,97... I have read
this topic, and I am not copletely sure, that it is the same problem. If it was, wouldn't be both the numbers stored in the variables as an exactly same closest representable number, which for 121.97 is 121.96999 99999 99998 86313 16227 83839 70260 62011 71875 ?
Now let's say that they are not stored as the same closest representable number. How do I find how exactly are they stored? When I look in the "CPU" debugging window, I am completely lost. I see the adresses, where those values should be, but nothing even similar to some binary, hexadecimal or whatever representation of the actual number... I admit, that advanced debugging is unknown universe to me...
Edit:
those two values really are slightly different.
OK, I don't need to understand everything. Although I am not dealing with money, there will be maximum 3 decimal places, so "currency" is the way out
BTW: The calculation is:
DATA[i].Meta.UnUsedAmount := DATA[i].AMOUNT - ObjQuery.FieldByName('USED').AsFloat;
In this case it is 3695 - 3573.03
For reasons unknown, you cannot view a float value (single/double or real48) as hexadecimal in the watch list.
However, you can still view the hexadecimal representation by viewing it as a memory dump.
Here's how:
Add the variable to the watch list.
Right click on the watch -> Edit Watch...
View it as memory dump
Now you can compare the two values in the debugger.
Never use floats for monetary amounts
You do know of course that you should not use floats to count money.
You'll get into all sorts of trouble with rounding and comparisons will not work the way you want them too.
If you want to work with money use the currency type instead. It does not have these problems, supports 4 decimal places and can be compared using the = operator with no rounding issues.
In your database you use the money or currency datatype.

Storing Prices with Cents in Rails

Ok I have a Stripe charge to which I am applying taxes. Stripe takes in a number as cents, so it leaves you with a number like 10015 instead of 100.15.
In my controller, I am sending the number to ActiveRecord as 10015/100.0
When I retrieve it, it gives me #<BigDecimal:7fca81f71130,'0.1243E3',18(27)>>
Whats going on ?
I tried
rails g migration add_expense_to_user expense:integer
and
rails g migration add_expense_to_user expense:decimal
to whose migration I added
add_column :user, :expense, :decimal, precision: 6, scale: 2
which is the current setup.
How do I store / retrieve the value if it is stored as 10015/100
The BigDecimal is just the type that Rails uses for decimal types in DBs. 0.1243E3 is scientific notation, short for 0.1243 x 10³ - ie. 124.3
You can get a regular float from it by just using the .to_f method in Ruby, or you can pass a BigDecimal into other Rails helpers, like number_to_currency(the_big_decimal) will produce "$124.30"
So, in other words, with the BigDecimal you probably already have what you're asking for in this question.
When you access the data, you need to call .to_f.
In irb:
a = BigDecimal.new(5, 2)
a
=> #<BigDecimal:1ad7c98,'0.5E1',9(27)>
a.to_f
=> 5.0
The value is stored inside the BigDecimal object with arbitrary precision. The "common" representation of non-integer values (i.e. floats) however doesn't provide this precision. Thus, BigDecimal provides various options to convert its value to other types.
You can e.g use expense.to_f to get a floating point representation of the BigDecimal value (and thus loosing the precision along the way). Alternatively, if you just want to print the value, you could use one of the to_s method to format the value as a string:
expense.to_s
# => "124.3"
See the BigDecimal documentation for details.

Is double ok for geo-coordinates in Java?

Hi i want to work with geocoordinates in java.
I've defined my Java variables as "double" and my Postgres Database is defined as "double precision".
I've heared of problems with float that 0.1 results sometimes in 0.09999...
It will have to store values like 50.081406 or 8.24481.
The values will be read from an Android-Device.
Do i have to worry about floating-point problems?
The issue with the floats is usually related to addition and subtraction where due to 2's compliment (how they are stored on the computer) they don't always round out exactly to what you want. That being said Doubles are a great way to store lat/lon
Also see: proper/best type for storing latitude and longitude

Rails is messing up BigDecimals by throwing in Floating Point Logic

I'm playing around with rails a bit and I have found something strange. For storing a money value I use the typical decimal data type which active record converts to BigDecimal. I considered this to be precise and I thought to avoid the odd behavior of floating point math. But when I store 99.99 to the db everything works fine, but when the records gets loaded by active record it loses precision and converts to something like 99.9899999999. This looks like a floating point issue.
I made some tests and found out that creating a BigDecimal like this b = BigDecimal.new("99.99") leads to a "clean" variable but building it this way b = BigDecimal.new(99.99) leads to the "unclean" version that I want to avoid.
I guess, that ActiveRecord reconstructs the BigDecimal with an intermediate float when loading the record from the database. This is not what I want and I would like to know if it can be avoided.
Ruby Version 1.9.3p0
Rails 3.2.9
Sqlite 3.7.9
Your problem is that you're using SQLite and SQLite doesn't have native support for numeric(m,n) data types. From the fine manual:
1.0 Storage Classes and Datatypes
Each value stored in an SQLite database (or manipulated by the database engine) has one of the following storage classes:
NULL. The value is a NULL value.
INTEGER. The value is a signed integer, stored in 1, 2, 3, 4, 6, or 8 bytes depending on the magnitude of the value.
REAL. The value is a floating point value, stored as an 8-byte IEEE floating point number.
TEXT. The value is a text string, stored using the database encoding (UTF-8, UTF-16BE or UTF-16LE).
BLOB. The value is a blob of data, stored exactly as it was input.
Read further down that page to see how SQLite's type system works.
Your 99.99 may be BigDecimal.new('99.99') in your Ruby code but it is almost certainly the REAL value 99.99 (i.e. an eight byte IEEE floating point value) inside SQLite and there goes the neighborhood.
So switch to a better database in your development environment; in particular, develop on top of whatever database you're going to be deploying on.
Don't use floating point for monetary values
Yes, exactly, SQLite is messing up your BigDecimal values.
The fundamental problem is that the FP format cannot store most decimal fractions correctly.
I believe you have about four choices:
Round everything to, say, two decimal places so that you never notice the slightly-off values.
Store your BigDecimal values in SQLite with the TEXT or BLOB storage class.
Use a different db that has some sort of decimal string support.
Scale everything to integral values and use the INTEGER storage class.
The problem is that FP fractions are rational numbers of the form x/2n. But the decimal monetary amounts have fractions that are x/(2n * 5m). The representations just aren't compatible. For example, in 0.01 ... 0.99, only 0.25, 0.50, and 0.75 have exact binary representations.

floating point precision in ruby on rails model validations

I am trying to validate a dollar amount using a regex:
^[0-9]+\.[0-9]{2}$
This works fine, but whenever a user submits the form and the dollar amount ends in 0(zero), ruby(or rails?) chops the 0 off.
So 500.00 turns into 500.0 thus failing the regex validation.
Is there any way to make ruby/rails keep the format entered by the user, regardless of trailing zeros?
I presume your dollar amount is of decimal type. So, any value user enters in the field is being cast from string to appropriate type before saving to the database. Validation applies to the values already converted to numeric types, so regex is not really a suitable validation filter in your case.
You have couple of possibilities to solve this, though:
Use validates_numericality_of. That way you leave the conversion completely to Rails, and just check whether the amount is within a given range.
Use validate_each method and code your validation logic yourself (e.g. check whether the value has more than 2 decimal digits).
Validate the attribute before it's been typecasted:
This is especially useful in
validation situations where the user
might supply a string for an integer
field and you want to display the
original string back in an error
message. Accessing the attribute
normally would typecast the string to
0, which isn‘t what you want.
So, in your case, you should be able to use:
validates_format_of :amount_before_type_cast, :with => /^[0-9]+\.[0-9]{2}$/, :message => "must contain dollars and cents, seperated by a period"
Note, however, that users might find it tedious to follow your rigid entry rules (I would really prefer being able to type 500 instead 500.00, for example), and that in some locales period is not a decimal separator (if you ever plan to internationalize your app).
In general if you wish to “remember” the decimal precision of a floating point value, you should use a decimal type, not a binary float.
On the other hand, I'm not certain why you would wish to force the string representation in such a strict manner… How about accepting any number and formatting it with e.g. number_to_currency?
Usually with money it's best to store it as an integer in cents (500 cents is $5.00). I use the Money gem to handle this.

Resources