Float in Ruby on Rails Json - ruby-on-rails

I faced a big problem: I have an API method, that returns JSON.
One of fields has property float and I need it to be 5.0. But when I convert it to JSON it becomes 5.
Even if I make this thing render :json => 5.to_f it returns me integer anyway.
What do I need to do to have 5.0 in JSON response?
Many Thanks

All numbers are floats in Javascript. Numbers are "double-precision 64-bit format IEEE 754 values".
see ECMAScript 2015 Language Specification.
What it means, is that, 5.0 and 5 are the same in JS. There is no differentiation of int, float or double.
As JSON (which stand for JavaScript Object Notation) generally end up as a JS object, 5 represents a float. Since JSON format is mostly used for data transfert/communication purpose, the decision to omit the the decimal part must be to save a few bytes in the string that is passed around.
In #z.shan's answer, the 5.0 is passed as a string "5.0".
Depending on what you want, I would recommend to keep the 5 as a number in the JSON payload.

All numbers are floats in Javascript. Numbers are "double-precision 64-bit format IEEE 754 values".
if you want to do then you should have to do like this
when we render json there is no floating points >0 that's why it is showing as integer you can convert it to string value to do this like
render json: 5.to_f.to_s
only if integer value is in object field then it will show as float

Or you can use conversion like that :
integer = 5
render json: ('%.2f'%integer)

Related

Dart: best type to store currency

In Java currency is usually stored in BigDecimal. But what to use to store currency values in Dart? BigInt doesn't seem to be a solution because it is for integer values only.
Definitely do not use doubles for an accounting application. Binary floating point numbers inherently cannot represent exact decimal values, which can lead to inaccurate calculations for seemingly trivial operations. Even though the errors will be small, they can eventually accumulate into larger errors. Setting decimal precision on binary numbers doesn't really make sense.
For currency, you instead either should something intended to store decimal values (e.g. package:decimal) or should use fixed-point arithmetic to store cents (or whatever the smallest amount of currency is that you want to track). For example, instead of using doubles to store values such as $1.23, use ints to store amounts in the smallest unit of currency (e.g. 123 cents). Then you can use helper classes to format the amounts wherever they're displayed. For example:
class Money {
int cents;
Money({required this.cents});
#override
String toString() => (cents / 100).toStringAsFixed(2);
Money operator +(Money other) => Money(cents: cents + other.cents);
// Add other operations as desired.
}

rails to_json quoting decimal values

(update)
An array of geocoordinates, built from a collection of records
[{"point_lon"=>0.1307336132e3, "point_lat"=>-0.252978933e2, "title"=>"kata tjuta"},
{"point_lon"=>0.154984876e3, "point_lat"=>-0.17e2, "title"=>"error case"},
{"point_lon"=>0.1310369614747e3, "point_lat"=>-0.253455545e2, "title"=>"uluru"}]
has proper quoting structure, but for JSON input to a javascript needs the rockets to be replaced by a colon.
Transforming the array via JSON.generate or to_json unfortunately leads to quoting of the decimal values and being ignored by the javascript
[{"point_lon":"130.7336132","point_lat":"-25.2978933","point_name":"kata tjuta"},
{"point_lon":"154.984876","point_lat":"-17.0","point_name":"error case"},
{"point_lon":"131.0369614747","point_lat":"-25.3455545","point_name":"uluru"}]
How can this array be transformed without quoting decimals?
This is because you use decimal numbers instead of float, so rails quotes the strings to preserve the precision. You can find methods to avoid this in this related question: Rails JSON Serialization of Decimal adds Quotes

Converting Double to NSNumber in Swift Loses Accuracy [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 6 years ago.
For some reason, certain Doubles in my Swift app are giving me trouble when converting to NSNumber, while some are not. My app needs to convert doubles with 2 decimal places (prices) to NSNumbers so they can be stored and retrieved using Core Data. For example, a few particular prices such as 79.99 would evaluate to 99.98999999999999 unless specifically formatted using NSNumber's doubleValue method.
Here selectedWarranty.price = 79.99 as shown in debugger
// item.price: NSNumber?
// selectedWarranty.price: Double?
item.price = NSNumber(double: selectedWarranty.price!)
I programmed some print statements to show how the conversion works out
Original double: 79.99
Converted to NSNumber: 79.98999999999999
.doubleValue Representation: 79.99
Can somebody explain if there is a reason why the initializer cannot surely keep 2 decimal places for every number? I would really like to store the prices in Core Data like they should be. Formatting every time it is displayed doesn't sound very convenient.
UPDATE:
Converted Core Data object to type NSDecimalNumber through data model, 79.99 and 99.99 no longer a problem, but now more manageable issue with different numbers...
Original double: 39.99
Converted to NSDecimalNumber: 39.99000000000001024
Firstly, you're confusing some terms. 79.98999999999999 is higher precision than 79.99 (it has a longer decimal expansion), but lower accuracy (it deviates from the true value).
Secondly, NSNumber does not store neither 79.99 nor 79.98999999999999. It stores the magnitude of the value according to the IEEE 754 standard. What you're seeing is likely the consequence of the printing logic that's applied to convert that magnitude into a human readable number. In any case, you should not be relying on Float or Double to store values with a fixed precision. By their very nature, they sacrifice precision in order to gain a longer range of representable values.
You would be much better off representing prices as an Int of cents, or as an NSDecimalNumber.
Please refer to Why not use Double or Float to represent currency?
That's how double works everywhere. If you need only 2 decimal places consider using integer/long instead adding point after second digit, when need to display the value.

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.

How do I avoid errors when converting strings to numbers if I don't know whether I have floats or integers?

I have stringgrid on delphi form and i am trying to divide values of one cell with value of another cell in another column.
But the problem is, stringgrid cells are populated with different types of numbers, so I am getting ConvertErrors.
For example the numbers in cells can look like
0.37 or 34 or 0.0013 or 0.00 or 0.35 or 30.65 or 45.9108 or 0.0307 or 6854.93.
In another words I never know is it going to be real, float, integer or any other kind of type in those cells.
I have looked everywhere on internet but no luck. Anyone any ideas. By the way I am not exactly Delphi expert. Thanks.
For each string, convert it first to a float value using StrToFloat function in SysUtils.pas . This should allow for any numerical type to be dealt with (unless you have something unusual like complex numbers). As you have some zero values in your list above you should also ensure that you check for divide by zero conditions as this will also potentially throw an exception.
SysUtils has many functions such as TryStrToFloat, TryStrToInt, TryStrToInt64 etc for this purpose. These functions accept a reference parameter (var parameter) for returning the converted value and function itself returns true if the conversion is successful.
If you are sure that the string has a valid number then you can check the input string to see if it has a decimal point before deciding which function to use.
Treat all the numbers as float. Use StrToFloat, divide the numbers, and then convert the result back to string with FloatToStr. If the result is an integer, no decimal point would be produced.

Resources