I'm working on parsing with haskell, I want to parse a timestamp value expressed in such a way
946685561.618847
I have no problem to recognize (parse) it, but my problem is about the type of the result. I think of two situations:
Is there a fractional type in Haskell so that the result can be associated with the fractional value?
If this is not the case then how to store this value, since Int range from -229 to 229 - 1?
There are actually multiple fractional types--there is even a whole Fractional class.
The most commonly used is a Double, which is a double-precision floating point number. You can also use Float which is single precision.
Another alternative is to use the Rational type, which lets you store a number as a ratio of two Integers. (Coincidentally, Integer is an unbounded integral type. Int is the name for the bounded version.)
These types (Double, Float and Rational) are good for storing rational values. If you just want to store a large integral value, use Integer which is unbounded. (That is, it can store arbitrarily sized integers.)
Related
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.
}
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.
I want to convert a double to a string and only display needed decimals.
So I cannot use
d := 123.4
s := Format('%.2f', [d]);
As it display as the result is 123.40 when I want 123.4.
Here is a table of samples and expected result
|Double|Result as string|
-------------------------
|5 |5 |
|5.1 |5.1 |
|5.12 |5.12 |
|5.123 |5.123 |
You can use the %g format string:
General: The argument must be a floating-point value. The value is converted to the shortest possible decimal string using fixed or
scientific format. The number of significant digits in the resulting
string is given by the precision specifier in the format string; a
default precision of 15 is assumed if no precision specifier is
present. Trailing zeros are removed from the resulting string, and a
decimal point appears only if necessary. The resulting string uses the
fixed-point format if the number of digits to the left of the decimal
point in the value is less than or equal to the specified precision,
and if the value is greater than or equal to 0.00001. Otherwise the
resulting string uses scientific format.
This is not as simple as you think. It all boils down to representability.
Let's consider a simple example of 0.1. That value is not exactly representable in double. This is because double is a binary representation rather than a decimal representation.
A double value is stored in the form s*2^e, where s and e are the significand and exponent respectively, both integers.
Back to 0.1. That value cannot be exactly represented as a binary floating point value. No combination of significand and exponent exist that represent it. Instead the closest representable value will be used:
0.10000 00000 00000 00555 11151 23125 78270 21181 58340 45410 15625
If this comes as a shock I suggest the following references:
Is floating point math broken?
http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html
http://floating-point-gui.de/
So, what to do? An obvious option is to switch to a decimal rather than binary representation. In Delphi that typically means using the Currency type. Depending on your application that might be a good choice, or it might be a terrible choice. If you wish to perform scientific or engineering calculations efficiently, for instance, then a decimal type is not appropriate.
Another option would be to look at how Python handles this. The repr function is meant, where possible, to yield a string with the property that eval(repr(x)) == x. In older versions of Python repr produced very long strings of the form 1.1000000000000001 when in fact 1.1 would suffice. Python adopted an algorithm that finds the shortest decimal expression that represents the floating point value. You could adopt the same approach. The snag is that the algorithm is very complex.
I have a function that returns a float value like this:
1.31584870815277
I need a function that returns TRUE comparing the value and the two numbers after the dot.
Example:
if 1.31584870815277 = 1.31 then ShowMessage('same');
Sorry for my english.
Can someone help me? Thanks
Your problem specification is a little vague. For instance, you state that you want to compare the values after the decimal point. In which case that would imply that you wish 1.31 to be considered equal to 2.31.
On top of this, you will need to specify how many decimal places to consider. A number like 1.31 is not representable exactly in binary floating point. Depending on the type you use, the closest representable value could be less than or greater than 1.31.
My guess is that what you wish to do is to use round to nearest, to a specific number of decimal places. You can use the SameValue function from the Math unit for this purpose. In your case you would write:
SameValue(x, y, 0.01)
to test for equality up to a tolerance of 0.01.
This may not be precisely what you are looking for, but then it's clear from your question that you don't yet know exactly what you are looking for. If your needs are specifically related to decimal representation of the values then consider using a decimal type rather than a binary type. In Delphi that would be Currency.
If speed isn't the highest priority, you can use string conversion:
if Copy(1.31584870815277.ToString, 1, 4) = '1.31' then ShowMessage('same');
Most of my applications revolve around financial calculations involving payments and interest rate calculations. I'm looking to find out how to determine what Delphi data type is best to use.
If I'm using a database to store these values and I've defined the fields in that database to be a decimal value with two decimal places, which Delphi datatype is most compatible with that scenario?
Should I use a rounding formula in Delphi to format the results to two decimal places before storing the values in the database? If so what is a best practice for doing so?
For such calculations, don't use floating point types like Real, Single or Double. They are not good with decimal values like 0.01 or 1234.995, as they must approximate them.
You can use Currency, a fixed point type, but that is still limited to 4 decimal places.
Try my Decimal type, which has 28-29 places and has a decimal exponent so it is ideal for such calculations. The only disadvantage is that it is not FPU supported (but written in assembler, nevertheless) so it is not as fast as the built-in types. It is the same as the Decimal type used in .NET (but a little faster) and quite similar to the one used on the Mac.
If you want to do financial calculations, don't use any of the floating-point/real types. Delphi has a Currency type, which is a fixed-point value with 4 decimal places, that should be just what you need.