TL;DR: You should use a decimal
data type instead of a float
or double
. You can declare your 0.001
as a decimal
by adding an m
after the value: 0.001m
The double
data type you chose relies on a representation of decimal numbers via a fraction of two integers. It is great for storing large decimal numbers with little memory, but it also means your number gets rounded to the closest value which can be represented by such a fraction. A decimal
on the other hand will store the information in a different way, which will more closely represent what you intuitively expect from decimal numbers.
More information about float values: https://floating-point-gui.de/
More information about numeric types declaration: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types
The documentation also explains:
Just as decimal fractions are unable to precisely represent some fractional values (such as 1/3 or Math.PI), binary fractions are unable to represent some fractional values. For example, 1/10, which is represented precisely by .1 as a decimal fraction, is represented by .001100110011 as a binary fraction, with the pattern "0011" repeating to infinity. In this case, the floating-point value provides an imprecise representation of the number that it represents. Performing additional mathematical operations on the original floating-point value often tends to increase its lack of precision.