Convert float to decimal, why need explicit conversion? - c#

i have known the decimal type is more preciser than float, so i think it should be reasonable that converting float to decimal will like converting float to double. But in realty, it doesn't true.
float a = 1.1f;
double d = a;
decimal c = (decimal)d; // true
decimal e = (decimal)a; // true
decimal f = a; // error

A float has the approximate range ±1.5 x 10−45 to ±3.4 x 1038
and a precision of 6-9 digits.
A decimal has the approximate range ±1.0 x 10-28 to ±7.9228 x 1028 and a precision of 28-29 digits.
It would cause an exception to assign a float to a decimal if the float is outside the decimal's range.
Therefore you get a compile error if you try to do that without casting. C# errs on the side of caution in these cases.
Here we can see the difference between range and precision.
A float has greater range than a decimal and a decimal has greater precision than a float.
(Note that you also get a compile error if you try to assign a decimal to a float without casting, but this time because it might lose data rather than because it would throw an exception.)

Related

Why does (float.MaxValue / float.MinValue) evaluate to Infinity?

Consider the following code and results:
double min = (double) float.MinValue;
double max = (double) float.MaxValue;
double epsilon = (double) float.Epsilon;
double range = max - min;
double delta = range / epsilon;
Console.WriteLine ($#"Min: [{min}].");
Console.WriteLine ($#"Max: [{max}].");
Console.WriteLine ($#"Epsilon: [{epsilon}].");
Console.WriteLine ($#"Range: [{range}].");
Console.WriteLine ($#"Delta: [{delta}].");
// Results:
// Min: [-3.4028234663852886E+38].
// Max: [3.4028234663852886E+38].
// Epsilon: [1.401298464324817E-45].
// Range: [6.805646932770577E+38].
// Delta: [4.8566719410840996E+83].
I was trying out some calculus, trying to get as close to Zero (0) as possible, and was surprised that I never thought about representing a numeric type's range before.
How would one represent a numeric type's range? In the case above, we're using Double to represent Single ranges. For Int32, we could use Int64, etc.
How would we represent ranges for Int64, Double, and Decimal, etc.?
Why does (float.MaxValue / float.Epsilon) evaluate to Infinity? Should it not evaluate to a number very close to, but less than float.MaxValue?
The numeric types in any programming language are approximations of mathematical concepts. Since these concepts include infinities, they cannot be represented accurately in real computers.
The range (defined as difference between the maximum and minimum value of a type) can only be represented by a type having a lager range. E.g., you could use decimal or System.Numerics.BigInteger to represent the range of Int64. BigInteger could also be used to represent the range of float and double or at least the integer part of it.
float.MaxValue / float.Epsilon: float.Epsilon is a positive number smaller than one (public const float Epsilon = 1.401298E-45;). If you divide a positive number by a positive number smaller than one, the result is lager than this number. E.g., 10 / 0.5 = 20. But since you cannot store a float bigger than float.MaxValue in a float, Microsoft decided to assign it Single.PositiveInfinity instead. They also could have decided the result should have been Single.NaN (Not a Number), Single.MaxValue or even to throw an exception. But that's how it was implemented. The Single type (float in C#`) complies with the IEC 60559:1989 (IEEE 754) standard for binary floating-point arithmetic.

Casting double to float all the 3 digits after decimal point is lost in C#

double temp = 136379828.125;
float m = (float)temp;
I ran above code and m value is 136379824.0
All the 3 digits '125' after decimal point is lost in double to float representation.
The closest 32 bit floating point value to 136379828.125 is 136379824.
In other words, the float data type does not have sufficient precision to represent your value. Note that your value is exactly representable in 64 bit double precision.

Double to Decimal without rounding after 15 digits

When converting a "high" precision Double to a Decimal I lose precision with Convert.ToDecimal or casting to (Decimal) due to Rounding.
Example :
double d = -0.99999999999999956d;
decimal result = Convert.ToDecimal(d); // Result = -1
decimal result = (Decimal)(d); // Result = -1
The Decimal value returned by Convert.ToDecimal(double) contains a maximum of 15 significant digits. If the value parameter contains more than 15 significant digits, it is rounded using rounding to nearest.
So I in order to keep my precision, I have to convert my double to a String and then call Convert.ToDecimal(String):
decimal result = System.Convert.ToDecimal(d.ToString("G20")); // Result = -0.99999999999999956d
This method is working but I would like to avoid using a String variable in order to convert a Double to Decimal without rounding after 15 digits?
One possible solution is to decompose d as the exact sum of n doubles, the last of which is small and contains all the trailing significant digits that you desire when converted to decimal, and the first (n-1) of which convert exactly to decimal.
For the source double d between -1.0 and 1.0:
decimal t = 0M;
bool b = d < 0;
if (b) d = -d;
if (d >= 0.5) { d -= 0.5; t = 0.5M; }
if (d >= 0.25) { d -= 0.25; t += 0.25M; }
if (d >= 0.125) { d -= 0.125; t += 0.125M; }
if (d >= 0.0625) { d -= 0.0625; t += 0.0625M; }
t += Convert.ToDecimal(d);
if (b) t = -t;
Test it on ideone.com.
Note that the operations d -= are exact, even if C# computes the binary floating-point operations at a higher precision than double (which it allows itself to do).
This is cheaper than a conversion from double to string, and provides a few additional digits of accuracy in the result (four bits of accuracy for the above four if-then-elses).
Remark: if C# did not allow itself to do floating-point computations at a higher precision, a good trick would have been to use Dekker splitting to split d into two values d1 and d2 that would convert each exactly to decimal. Alas, Dekker splitting only works with a strict interpretation of IEEE 754 multiplication and addition.
Another idea is to use C#'s version of frexp to obtain the significand s and exponent e of d, and to compute (Decimal)((long) (s * 4503599627370496.0d)) * <however one computes 2^e in Decimal>.
There are two approaches, one of which will work for values up below 2^63, and the other of which will work for values larger than 2^53.
Split smaller values into whole-number and fractional parts. The whole-number part may be precisely cast to long and then Decimal [note that a direct cast to Decimal may not be precise!] The fractional part may be precisely multiplied by 9007199254740992.0 (2^53), converted to long and then Decimal, and then divided by 9007199254740992.0m. Adding the result of that division to the whole-number part should yield a Decimal value which is within one least-significant-digit of being correct [it may not be precisely rounded, but will still be far better than the built-in conversions!]
For larger values, multiply by (1.0/281474976710656.0) (2^-48), take the whole-number part of that result, multiply it back by 281474976710656.0, and subtract it from the original result. Convert the whole-number results from the division and the subtraction to Decimal (they should convert precisely), multiply the former by 281474976710656m, and add the latter.

Why does integer division in C# return an integer and not a float?

Does anyone know why integer division in C# returns an integer and not a float?
What is the idea behind it? (Is it only a legacy of C/C++?)
In C#:
float x = 13 / 4;
//== operator is overridden here to use epsilon compare
if (x == 3.0)
print 'Hello world';
Result of this code would be:
'Hello world'
Strictly speaking, there is no such thing as integer division (division by definition is an operation which produces a rational number, integers are a very small subset of which.)
While it is common for new programmer to make this mistake of performing integer division when they actually meant to use floating point division, in actual practice integer division is a very common operation. If you are assuming that people rarely use it, and that every time you do division you'll always need to remember to cast to floating points, you are mistaken.
First off, integer division is quite a bit faster, so if you only need a whole number result, one would want to use the more efficient algorithm.
Secondly, there are a number of algorithms that use integer division, and if the result of division was always a floating point number you would be forced to round the result every time. One example off of the top of my head is changing the base of a number. Calculating each digit involves the integer division of a number along with the remainder, rather than the floating point division of the number.
Because of these (and other related) reasons, integer division results in an integer. If you want to get the floating point division of two integers you'll just need to remember to cast one to a double/float/decimal.
See C# specification. There are three types of division operators
Integer division
Floating-point division
Decimal division
In your case we have Integer division, with following rules applied:
The division rounds the result towards zero, and the absolute value of
the result is the largest possible integer that is less than the
absolute value of the quotient of the two operands. The result is zero
or positive when the two operands have the same sign and zero or
negative when the two operands have opposite signs.
I think the reason why C# use this type of division for integers (some languages return floating result) is hardware - integers division is faster and simpler.
Each data type is capable of overloading each operator. If both the numerator and the denominator are integers, the integer type will perform the division operation and it will return an integer type. If you want floating point division, you must cast one or more of the number to floating point types before dividing them. For instance:
int x = 13;
int y = 4;
float x = (float)y / (float)z;
or, if you are using literals:
float x = 13f / 4f;
Keep in mind, floating points are not precise. If you care about precision, use something like the decimal type, instead.
Since you don't use any suffix, the literals 13 and 4 are interpreted as integer:
Manual:
If the literal has no suffix, it has the first of these types in which its value can be represented: int, uint, long, ulong.
Thus, since you declare 13 as integer, integer division will be performed:
Manual:
For an operation of the form x / y, binary operator overload resolution is applied to select a specific operator implementation. The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.
The predefined division operators are listed below. The operators all compute the quotient of x and y.
Integer division:
int operator /(int x, int y);
uint operator /(uint x, uint y);
long operator /(long x, long y);
ulong operator /(ulong x, ulong y);
And so rounding down occurs:
The division rounds the result towards zero, and the absolute value of the result is the largest possible integer that is less than the absolute value of the quotient of the two operands. The result is zero or positive when the two operands have the same sign and zero or negative when the two operands have opposite signs.
If you do the following:
int x = 13f / 4f;
You'll receive a compiler error, since a floating-point division (the / operator of 13f) results in a float, which cannot be cast to int implicitly.
If you want the division to be a floating-point division, you'll have to make the result a float:
float x = 13 / 4;
Notice that you'll still divide integers, which will implicitly be cast to float: the result will be 3.0. To explicitly declare the operands as float, using the f suffix (13f, 4f).
Might be useful:
double a = 5.0/2.0;
Console.WriteLine (a); // 2.5
double b = 5/2;
Console.WriteLine (b); // 2
int c = 5/2;
Console.WriteLine (c); // 2
double d = 5f/2f;
Console.WriteLine (d); // 2.5
It's just a basic operation.
Remember when you learned to divide. In the beginning we solved 9/6 = 1 with remainder 3.
9 / 6 == 1 //true
9 % 6 == 3 // true
The /-operator in combination with the %-operator are used to retrieve those values.
The result will always be of type that has the greater range of the numerator and the denominator. The exceptions are byte and short, which produce int (Int32).
var a = (byte)5 / (byte)2; // 2 (Int32)
var b = (short)5 / (byte)2; // 2 (Int32)
var c = 5 / 2; // 2 (Int32)
var d = 5 / 2U; // 2 (UInt32)
var e = 5L / 2U; // 2 (Int64)
var f = 5L / 2UL; // 2 (UInt64)
var g = 5F / 2UL; // 2.5 (Single/float)
var h = 5F / 2D; // 2.5 (Double)
var i = 5.0 / 2F; // 2.5 (Double)
var j = 5M / 2; // 2.5 (Decimal)
var k = 5M / 2F; // Not allowed
There is no implicit conversion between floating-point types and the decimal type, so division between them is not allowed. You have to explicitly cast and decide which one you want (Decimal has more precision and a smaller range compared to floating-point types).
As a little trick to know what you are obtaining you can use var, so the compiler will tell you the type to expect:
int a = 1;
int b = 2;
var result = a/b;
your compiler will tell you that result would be of type int here.

C#: divide an int by 100

How do I divide an int by 100?
eg:
int x = 32894;
int y = 32894 / 100;
Why does this result in y being 328 and not 328.94?
When one integer is divided by another, the arithmetic is performed as integer arithmetic.
If you want it to be performed as float, double or decimal arithmetic, you need to cast one of the values appropriately. For example:
decimal y = ((decimal) x) / 100;
Note that I've changed the type of y as well - it doesn't make sense to perform decimal arithmetic but then store the result in an int. The int can't possibly store 328.94.
You only need to force one of the values to the right type, as then the other will be promoted to the same type - there's no operator defined for dividing a decimal by an integer, for example. If you're performing arithmetic using several values, you might want to force all of them to the desired type just for clarity - it would be unfortunate for one operation to be performed using integer arithmetic, and another using double arithmetic, when you'd expected both to be in double.
If you're using literals, you can just use a suffix to indicate the type instead:
decimal a = x / 100m; // Use decimal arithmetic due to the "m"
double b = x / 100.0; // Use double arithmetic due to the ".0"
double c = x / 100d; // Use double arithmetic due to the "d"
double d = x / 100f; // Use float arithmetic due to the "f"
As for whether you should be using decimal, double or float, that depends on what you're trying to do. Read my articles on decimal floating point and binary floating point. Usually double is appropriate if you're dealing with "natural" quantities such as height and weight, where any value will really be an approximation; decimal is appropriate with artificial quantities such as money, which are typically represented exactly as decimal values to start with.
328.94 is not an integer. Integer / divide rounds down; that is how it works.
I suggest you cast to decimal:
decimal y = 32894M / 100;
or with variables:
decimal y = (decimal)x / 100;
Because an int is only a whole number. Try this instead.
int x = 32894;
double y = x / 100.0;
Because you're doing integer division. Add a period behind the 100 and you'll get a double instead.
When you divide two integers, the result is an integer. Integers don't have decimal places, so they're just truncated.
its programming fundamental that int(integer) dividing is different from float(floating point) dividing.
if u want .94 use float or double
var num = 3294F/100F

Categories