1

I have long vairable long x = 231021578; and when I convert it to float like float y = x; the value of y will be 231021584

I want to know why this happen. Float is stored in 4 bytes and its range is from ±1.5x10^−45 to ±3.4x10^38 and this value is between this range.

I want to know the concept behind this change I searched alot but I didn't reach anything.

Hamed
  • 17
  • 3
  • 2
    From the 32 bits of a float, only 23 are for the mantissa, so float has a precision of about 7 digits (see e.g. https://learn.microsoft.com/en-us/cpp/c-language/type-float) – Klaus Gütter Feb 19 '22 at 13:21
  • Does this answer your question? [Why are floating point numbers inaccurate?](https://stackoverflow.com/questions/21895756/why-are-floating-point-numbers-inaccurate) – Charlieface Feb 19 '22 at 21:14
  • @KlausGütter Detail: [Off-by-1.](https://stackoverflow.com/questions/71185286/convert-long-to-float-changing-the-number-c-sharp#comment125830785_71185286) Typical [`float`](https://en.wikipedia.org/wiki/Single-precision_floating-point_format#IEEE_754_single-precision_binary_floating-point_format:_binary32) has a 24-bit _significand_, not a 23-bit _mantissa_. The encoding stores 23-bits explicitly and 1 bit implicitly. – chux - Reinstate Monica Feb 20 '22 at 13:09
  • Does this answer your question? [Difference between decimal, float and double in .NET?](https://stackoverflow.com/questions/618535/difference-between-decimal-float-and-double-in-net) – Chris Schaller Feb 20 '22 at 13:26

2 Answers2

0

A 4-byte object can encode, at most, 232 different values.

Do not expect a float, with its typically 24 bit precision, to encode exactly every integer value from 0 to ±3.4x1038.

231021578 (0xDC5 1C0A), with its 27 leading significant bits*1, is not one of those float. The closest float is 231021584 (0xDC5 1C10). That has 24 or less significant bits*2.


*1

Hex: 0xDC5 1C0A
Bin: 1101 1100 0101 0001 1100 0000 1010
     ^-------------------------------^ 27 significant leading bits.

*2

Hex: 0xDC5 1C10
Bin: 1101 1100 0101 0001 1100 0001 0000
     ^---------------------------^     24 significant leading bits.
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
-1

Floats are an approximation and cannot easily represent ALL rational values with only 4 bytes, long is 8 bytes, so you expect to lose some information when you convert the value to a type with less precision, but on top of that float is stored differently, using base-2 notation, where as integral types like long are stored using base-10.

You will get better results with double or decimal

As a general rule I use decimal for discrete values that you need to maintain their exact value to a specific number of decimal places 100% of the time, for instance for monetary values on invoices and transactions. Many other measurements are acceptable to be stored and processed using double.

The key take-away is that double is better for un unspecified number of decimal places, where as decimal is suited for implementations that have a fixed number of decimal places. Both of these concepts can lead to rounding errors at different points in your logic, decimal forces you to deliberately deal with rounding up front, double allows you to defer management of rounding until you need to display the value.

long x = 231021578;
float y = x;
double z = x;
decimal m = x;

Console.WriteLine("long: {0}", x);
Console.WriteLine("float: {0}", y);
Console.WriteLine("double: {0}", z);
Console.WriteLine("decimal: {0}", m);

Results:

long: 231021578
float: 2.310216E+08
double: 231021578
decimal: 231021578

Its out of scope for this post, but there was a healthy discussion related to this 10 years ago: Why is the data stored in a Float datatype considered to be an approximate value?

Chris Schaller
  • 13,704
  • 3
  • 43
  • 81
  • 3
    Re “Floats are an approximation”: This is not the correct model. As specified by the IEEE-754 standard for floating-point arithmetic, each `float` represents one number (or NaN) exactly; it is not an approximation. It is not the numbers that are approximations but the operations. Each floating-point operation returns a result equal to rounding the result of the corresponding real-number operation to the nearest representable value (according to a chosen rounding rule). This includes conversion from other formats into floating-point… – Eric Postpischil Feb 19 '22 at 14:23
  • … Understanding this model is crucial for understanding and analyzing floating-point arithmetic, designing and debugging software for it, and writing proofs about it. – Eric Postpischil Feb 19 '22 at 14:24
  • 1
    Re “`decimal` for discrete values that you need to maintain their exact value 100% of the time”: This is not correct. For example, Quicken uses decimal but fails to track the correct basis for my lots of Apple stock after it split 7:1. This causes discrepancies in tax reporting for years to come. – Eric Postpischil Feb 19 '22 at 14:26
  • Thanks @EricPostpischil all technically correct, but we need to take a practical view point to explain complex concepts in this forum. In general for C#, decimal will solve a lot of problems with data at rest, double will solve a lot of problems with calculations, especially divisions. C# decimal has much higher precision for decimal places, at the cost of a lower max value. It is specifically the conversion between integral types and floating point types where issues generally occur. using `double` instead of `single` as suggested in this post will get around most of those issues. – Chris Schaller Feb 20 '22 at 01:39
  • Quickens issues with decimal has a lot to with the implementation and usage of decimal in their language and storage, and nothing to do with c#. It actually looks like Quicken's decimal is integer based and divided by 1000, this is common in databases, SQL Server `MONEY` is a common example of that. We all agree that it is important to gain an understanding in these concepts if you are crunching numbers in your application logic, but if you are using integral types as input you will easily run into issues with single precision floating point `float` in c# – Chris Schaller Feb 20 '22 at 01:43
  • It is important to keep this in the context of c#, this article covers some specific issues that decimal solves, keep in mind that it is data at rest that is key, storing in decimal form and retrieving it will be guaranteed not to change, that forces you to deal with any rounding issues that may occur before you store the values, especially for irrational numbers. https://zetcode.com/csharp/decimal/ – Chris Schaller Feb 20 '22 at 01:50
  • Chris Schaller, "Floats are an approximation" --> All finite floating point values are exact. Conversion from a large integer to a `float` may approximate as compared to math. – chux - Reinstate Monica Feb 20 '22 at 13:14