C# Decimal.Epsilon - c#

Why doesn't Decimal data type have Epsilon field?
From the manual, the range of decimal values is ±1.0 × 10e−28 to ±7.9 × 10e28.
The description of Double.Epsilon:
Represents the smallest positive Double value greater than zero
So it seems, Decimal has such a (non-trivial) value too. But why isn't it easily accessible?
I do understand that +1.0 × 10e−28 is exactly the smallest positive Decimal value greater than zero:
decimal Decimal_Epsilon = new decimal(1, 0, 0, false, 28); //1e-28m;
By the way, there are a couple of questions that give information about Decimal data type's internal representation:
decimal in c# misunderstanding?
What's the second minimum value that a decimal can represent?
Here's an example where Epsilon would be useful.
Lets say I have a weighted sum of values from some sampling set and sum of weights (or count) of samples taken. Now I want to compute the weighted mean value. But I know that the sum of weights (or count) may be still zero. To prevent division by zero I could do if... else... and check for the zero. Or I could write like this:
T weighted_mean = weighted_sum / (weighted_count + T.Epsilon)
This code is shorter in my eye. Or, alternatively I can skip the + T.Epsilon and instead initialize with:
T weighted_count = T.Epsilon;
I can do this when I know that the values of real weights are never close to Epsilon.
And for some data types and use cases this is maybe even faster since it does not involve branches. As I understand, the processors are not able to take both branches for computation, even when the branches are short. And I may know that the zeros occur randomly at 50% rate :=) For Decimal, the speed aspect is likely not important or even positively useful in the first case though.
My code may be generic (for example, generated) and I do not want to write separate code for decimals. Therefore one would like to see that Decimal have similar interface as other real-valued types.

Contrary to that definition, epsilon is actually a concept used to eliminate the ambiguity of conversion between binary and decimal representations of values. For example, 0.1 in decimal doesn't have a simple binary representation, so when you declare a double as 0.1, it is actually setting that value to an approximate representation in binary. If you add that binary representation number to itself 10 times (mathematically), you get a number that is approximately 1.0, but not exactly. An epsilon will let you fudge the math, and say that the approximate representation of 0.1 added to itself can be considered equivalent to the approximate representation of 0.2.
This approximation that is caused by the nature of the representations is not needed for the decimal value type, which is already a decimal representation. This is why any time you need to deal with actual numbers and numbers which are themselves not approximations (i.e. money as opposed to mass), the correct floating point type to use is decimal and not double.

Smallest number I can calculate for decimal is:
public static decimal DecimalEpsilon = (decimal) (1 / Math.Pow(10, 28));
This is from running the following in a C# Interactive Window:
for (int power = 0; power <= 50; power++) { Console.WriteLine($"1 / 10^{power} = {((decimal)(1 / (Math.Pow(10, power))))}"); }
Which has the following output:
1 / 10^27 = 0.000000000000000000000000001
1 / 10^28 = 0.0000000000000000000000000001
1 / 10^29 = 0
1 / 10^30 = 0

If we just think about the 96 bit mantissa, the Decimal type can be thought of as having an epsilon equal to the reciprocal of a BigInteger constructed with 96 set bits. That is obviously too small a number to represent with current intrinsic value types.
In other words, we would need a "BigReal" value to represent such a small fraction.
And frankly, that is just the "granularity" of the epsilon. We would then need to know the exponent (bits 16-23 of the highest Int32 from GetBits()) to arrive at the "real" epsilon for a GIVEN decimal value.
Obviously, the meaning of "epsilon" for Decimal is variable. You can use the granularity epsilon with the exponent and come up with a specific epsilon for a GIVEN decimal.
But consider the following rather problematic situation:
[TestMethod]
public void RealEpsilonTest()
{
var dec1 = Decimal.Parse("1.0");
var dec2 = Decimal.Parse("1.00");
Console.WriteLine(BitPrinter.Print(dec1, " "));
Console.WriteLine(BitPrinter.Print(dec2, " "));
}
DEC1: 00000000 00000001 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00001010
DEC2; 00000000 00000010 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 01100100
Despite the two parsed values seemingly being equal, their representation is not the same!
The moral of the story is... be very careful that you thoroughly understand Decimal before THINKING that you understand it !!!
HINT:
If you want the epsilon for Decimal (theoretically), create a UNION ([StructLayout[LayoutKind.Explicit]) combining Decimal(128 bits) and BigInteger(96 bits) and Exponent(8 bits). The getter for Epsilon would return the correct BigReal value based on granularity epsilon and exponent; assuming, of course, the existence of a BigReal definition (which I've been hearing for quite some time, will be coming).
The granularity epsilon, by the way, would be a constant or a static field...
static grain = new BigReal(1 / new BitInteger(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF });
HOMEWORK: Should the last byte to BigInteger be 0xFF or 0x7F (or something else altogether)?
PS: If all of that sounds rather more complicated than you were hoping, ... consider that comp science pays reasonably well. /-)

Related

What are the chances of Random.NextDouble being exactly 0?

The documentation of Random.NextDouble():
Returns a random floating-point number that is greater than or equal to 0.0, and less than 1.0.
So, it can be exactly 0. But what are the chances for that?
var random = new Random();
var x = random.NextDouble()
if(x == 0){
// probability for this?
}
It would be easy to calculate the probability for Random.Next() being 0, but I have no idea how to do it in this case...
As mentioned in comments, it depends on internal implementation of NextDouble. In "old" .NET Framework, and in modern .NET up to version 5, it looks like this:
protected virtual double Sample() {
return (InternalSample()*(1.0/MBIG));
}
InternalSample returns integer in 0 to Int32.MaxValue range, 0 included, int.MaxValue excluded. We can assume that the distribution of InternalSample is uniform (in the docs for Next method, which just calls InternalSample, there are clues that it is, and it seems there is no reason to use non-uniform distribution in general-purpose RNG for integers). That means every number is equally likely. Then, we have 2,147,483,647 numbers in distribution, and the probability to draw 0 is 1 / 2,147,483,647.
In modern .NET 6+ there are two implementations. First is used when you provide explicit seed value to Random constructor. This implementation is the same as above, and is used for compatibility reasons - so that old code relying on the seed value to produce deterministic results will not break while moving to the new .NET version.
Second implementation is a new one and is used when you do NOT pass seed into Random constructor. Source code:
public override double NextDouble() =>
// As described in http://prng.di.unimi.it/:
// "A standard double (64-bit) floating-point number in IEEE floating point format has 52 bits of significand,
// plus an implicit bit at the left of the significand. Thus, the representation can actually store numbers with
// 53 significant binary digits. Because of this fact, in C99 a 64-bit unsigned integer x should be converted to
// a 64-bit double using the expression
// (x >> 11) * 0x1.0p-53"
(NextUInt64() >> 11) * (1.0 / (1ul << 53));
We first obtain random 64-bit unsigned integer. Now, we could multiply it by 1 / 2^64 to obtain double in 0..1 range, but that would make the resulting distribution biased. double is represented by 53-bit mantissa (52 bits are explicit and one is implicit) ,exponent and sign. For all integer values exponent is the same, so that leaves us with 53 bits to represent integer values. But we have 64-bit integer here. This means integer values less than 2^53 can be represented exactly by double but bigger integers can not. For example:
ulong l1 = 1ul << 53;
ulong l2 = l1 + 1;
double d1 = l1;
double d2 = l2;
Console.WriteLine(d1 == d2);
Prints "true", so two different integers map to the same double value. That means if we just multiply our 64-bit integer by 1 / 2^64 - we'll get a biased non-uniform distribution, because many integers bigger than 2^53-1 will map to the same values.
So instead, we throw away 11 bits, and multiply the result by 1 / 2^53 to get uniform distibution in 0..1 range. The probability to get 0 is then 1 / 2^53 (1 / 9,007,199,254,740,992). This implementation is better than the old one, because is provides much more different doubles in 0 .. 1 range (2^53 compared to 2^32 in old one).
You also asked in comments:
If one knows how many numbers there are between 0 inclusive and 1
exclusive (according to IEEE 754), it would be possible to answer the
'probability' question, because 0 is one of all of them
That's not so. There are actually more than 2^53 representable numbers between 0..1 in IEEE 754. We have 52 bits of mantissa, then we have 11 bits of exponent, half of which is for negative exponents. Almost all negative exponents (rougly half of that 11 bit range) combined with mantissa gives us distinct value in 0..1 range.
Why we can't use full 0..1 range which IEEE allows us to generate random number? Because this range is not uniform (like the full double range is not uniform itself). For example there are more representable numbers in 0 .. 0.5 range than in 0.5 .. 1 range.
This is from a strictly academic persepective.
From Double Struct:
All floating-point numbers also have a limited number of significant
digits, which also determines how accurately a floating-point value
approximates a real number. A Double value has up to 15 decimal digits
of precision, although a maximum of 17 digits is maintained
internally. This means that some floating-point operations may lack
the precision to change a floating point value.
If only 15 decimal digits are significant, then your possible return values are:
0.000000000000000
To:
0.999999999999999
Said differently, you have 10^15 possible (comparably different, "distinct") values (see Permutations in the first answer):
10^15 = 1,000,000,000,000,000
Zero is just ONE of those possibilities:
1 / 1,000,000,000,000,000 = 0.000000000000001
Stated as a percentage:
0.0000000000001% chance of zero being randomly selected?
I think this is the closest "correct" answer you're going to get...
...whether it performs this way in practice is possibly a different story.
Just create a simple program, and let it run until you are satisfied by the number of tries done. (see: https://onlinegdb.com/ij1M50gRQ)
Random r = new Random();
Double d ;
int attempts=0;
int attempts0=0;
while (true) {
d = Math.Round(r.NextDouble(),3);
if(d==0) attempts0++;
attempts++;
if (attempts%1000000==0) Console.WriteLine($"Attempts: {attempts}, with {attempts0} times a 0 value, this is {Math.Round(100.0*attempts0/attempts,3)} %");
}
example output:
...
Attempts: 208000000, with 103831 times a 0 value, this is 0.05 %
Attempts: 209000000, with 104315 times a 0 value, this is 0.05 %
Attempts: 210000000, with 104787 times a 0 value, this is 0.05 %
Attempts: 211000000, with 105305 times a 0 value, this is 0.05 %
Attempts: 212000000, with 105853 times a 0 value, this is 0.05 %
Attempts: 213000000, with 106349 times a 0 value, this is 0.05 %
Attempts: 214000000, with 106839 times a 0 value, this is 0.05 %
...
Changing the value of d to be rounded to 2 decimals will return 0.5%

Double vs Decimal Rounding in C#

Why does:
double dividend = 1.0;
double divisor = 3.0;
Console.WriteLine(dividend / divisor * divisor);
output 1.0,
but:
decimal dividend = 1;
decimal divisor = 3;
Console.WriteLine(dividend / divisor * divisor);
outputs 0.9999999999999999999999999999
?
I understand that 1/3 can't be computed exactly, so there must be some rounding.
But why does Double round the answer to 1.0, but Decimal does not?
Also, why does double compute 1.0/3.0 to be 0.33333333333333331?
If rounding is used, then wouldn't the last 3 get rounded to 0, why 1?
Why 1/3 as a double is 0.33333333333333331
The closest way to represent 1/3 in binary is like this:
0.0101010101...
That's the same as the series 1/4 + (1/4)^2 + (1/4)^3 + (1/4)^4...
Of course, this is limited by the number of bits you can store in a double. A double is 64 bits, but one of those is the sign bit and another 11 represent the exponent (think of it like scientific notation, but in binary). So the rest, which is called the mantissa or significand is 52 bits. Assume a 1 to start and then use two bits for each subsequent power of 1/4. That means you can store:
1/4 + 1/4^2 + ... + 1/4 ^ 27
which is 0.33333333333333331
Why multiplying by 3 rounds this to 1
So 1/3 represented in binary and limited by the size of a double is:
0.010101010101010101010101010101010101010101010101010101
I'm not saying that's how it's stored. Like I said, you store the bits starting after the 1, and you use separate bits for the exponent and the sign. But I think it's useful to consider how you'd actually write it in base 2.
Let's stick with this "mathematician's binary" representation and ignore the size limits of a double. You don't have to do it this way, but I find it convenient. If we want to take this approximation for 1/3 and multiply by 3, that's the same as bit shifting to multiply by 2 and then adding what you started with. This gives us 1/3 * 3 = 0.111111111111111111111111111111111111111111111111111111
But can a double store that? No, remember, you can only have 52 bits of mantissa after the first 1, and that number has 54 ones. So we know that it'll be rounded, in this case rounded up to exactly 1.
Why for decimal you get 0.9999999999999999999999999999
With decimal, you get 96 bits to represent an integer, with additional bits representing the exponent up to 28 powers of 10. So even though ultimately it's all stored as binary, here we're working with powers of 10 so it makes sense to think of the number in base 10. 96 bits lets us express up to 79,228,162,514,264,337,593,543,950,335, but to represent 1/3 we're going to go with all 3's, up to the 28 of them that we can shift to the right of the decimal point: 0.3333333333333333333333333333.
Multiplying this approximation for 1/3 by 3 gives us a number we can represent exactly. It's just 28 9's, all shifted to the right of the decimal point: 0.9999999999999999999999999999. So unlike with double's there's not a second round of rounding at this point.
This is by design of the decimal type which is optimized for accuracy unlike the double type which is optimized for low accuracy but higher performance.
The Decimal value type represents decimal numbers ranging from positive 79,228,162,514,264,337,593,543,950,335 to negative 79,228,162,514,264,337,593,543,950,335.
The Decimal value type is appropriate for financial calculations requiring large numbers of significant integral and fractional digits and no round-off errors. The Decimal type does not eliminate the need for rounding. Rather, it minimizes errors due to rounding. Thus your code produces a result of 0.9999999999999999999999999999 rather than 1.
One reason that infinite decimals are a necessary extension of finite decimals is to represent fractions. Using long division, a simple division of integers like 1⁄9 becomes a recurring decimal, 0.111…, in which the digits repeat without end. This decimal yields a quick proof for 0.999… = 1. Multiplication of 9 times 1 produces 9 in each digit, so 9 × 0.111… equals 0.999… and 9 × 1⁄9 equals 1, so 0.999… = 1:

Check if decimal contains decimal places by looking at the bytes

There is a similar question in here. Sometimes that solution gives exceptions because the numbers might be to large.
I think that if there is a way of looking at the bytes of a decimal number it will be more efficient. For example a decimal number has to be represented by some n number of bytes. For example an Int32 is represented by 32 bits and all the numbers that start with the bit of 1 are negative. Maybe there is some kind of similar relationship with decimal numbers. How could you look at the bytes of a decimal number? or the bytes of an integer number?
If you are really talking about decimal numbers (as opposed to floating-point numbers), then Decimal.GetBits will let you look at the individual bits of a decimal. The MSDN page also contains a description of the meaning of the bits.
On the other hand, if you just want to check whether a number has a fractional part or not, doing a simple
var hasFractionalPart = (myValue - Math.Round(myValue) != 0)
is much easier than decoding the binary structure. This should work for decimals as well as classic floating-point data types such as float or double. In the latter case, due to floating-point rounding error, it might make sense to check for Math.Abs(myValue - Math.Round(myValue)) < someThreshold instead of comparing to 0.
If you want a reasonably efficient way of getting the 'decimal' value of a decimal type you can just mod it by one.
decimal number = 4.75M;
decimal fractionalPart = number % 1;
Console.WriteLine(fractionalPart); //will print 0.75
While it may not be the theoretically optimal solution, it'll be quite fast, and almost certainly fast enough for your purposes (far better than string manipulation and parsing, which is a common naive approach).
You can use Decimal.GetBits in order to retrieve the bits from a decimal structure.
The MSDN page linked above details how they are laid out in memory:
The binary representation of a Decimal number consists of a 1-bit sign, a 96-bit integer number, and a scaling factor used to divide the integer number and specify what portion of it is a decimal fraction. The scaling factor is implicitly the number 10, raised to an exponent ranging from 0 to 28.
The return value is a four-element array of 32-bit signed integers.
The first, second, and third elements of the returned array contain the low, middle, and high 32 bits of the 96-bit integer number.
The fourth element of the returned array contains the scale factor and sign. It consists of the following parts:
Bits 0 to 15, the lower word, are unused and must be zero.
Bits 16 to 23 must contain an exponent between 0 and 28, which indicates the power of 10 to divide the integer number.
Bits 24 to 30 are unused and must be zero.
Bit 31 contains the sign; 0 meaning positive, and 1 meaning negative.
Going with Oded's detailed info to use GetBits, I came up with this
const int EXP_MASK = 0x00FF0000;
bool hasDecimal = (Decimal.GetBits(value)[3] & EXP_MASK) != 0x0;

How to convert negative number to positive by |= Operator in C#?

We all know that the highest bit of an Int32 defines its sign. 1 indicates that it's negative and 0 that it's positive (possibly reversed). Can I convert a negative number to a positive one by changing its highest bit?
I tried to do that using the following code:
i |= Int32.MaxValue;
But it doesn't work.
Why don't you just use the Math.Abs(yourInt) method? I don't see the necessity to use bitwise operations here.
If you are just looking for a bitwise way to do this (like an interview question, etc), you need to negate the number (bitwise) and add 1:
int x = -13;
int positiveX = ~x + 1;
This will flip the sign if it's positive or negative. As a small caveat, this will NOT work if x is int.MinValue, though, since the negative range is one more than the positive range.
Of course, in real world code I'd just use Math.Abs() as already mentioned...
The most-significant bit defines it's sign, true. But that's not everything:
To convert a positive number to a negative one, you have to:
Negate the number (for example, +1, which is 0000 0001 in binary, turns into 1111 1110)
Add 1 (1111 1110 turns into 1111 1111, which is -1)
That process is known as Two's complement.
Inverting the process is equally simple:
Substract 1 (for example, -1, 1111 1111 turns into 1111 1110)
Negate the number (1111 1110 turns into 0000 0001, which is +1 again).
As you can see, this operation is impossible to implement using the binary or-operator. You need the bitwise-not and add/substract.
The above examples use 8-bit integers, but the process works exactly the same for all integers. Floating-point numbers, however, use only a sign bit.
If you're talking about using bitwise operations, it won't work like that. I'm assuming you were thinking you'd flip the highest bit (the sign flag) to get the negative, but it won't work as you expect.
The number 6 is represented as 00000000 00000000 00000000 00000110 in a 32-bit signed integer. If you flip the highest bit (the signing bit) to 1, you'll get 10000000 00000000 00000000 00000110, which is -2147483642 in decimal. Not exactly what you expected, I should imagine. This is because negative numbers are stored in "negative logic", which means that 11111111 11111111 11111111 11111111 is -1.
If you flip every bit in a positive value x, you get -(x+1). For example:
00000000 00000000 00000000 00000110 = 6
11111111 11111111 11111111 11111001 = -7
You've still got to use an addition (or subtraction) to produce the correct result, though.
I just solved this by doing:
Int a = IntToSolve; //Whatever int you want
b = a < 0 ? a*-1 : a*1 ;
Doing this will output only positive ints.
The other way around would be:
Int a = IntToSolve; //Same but from positive to negative
b = a < 0 ? a*1 : a*-1 ;
Whats wrong with Math.Abs(i) if you want to go from -ve to +ve, or -1*i if you want to go both ways?
It's impossible with the |= operator. It cannot unset bits. And since the sign bit is set on negative numbers you can't unset it.
Your quest is, sadly, futile. The bitwise OR operator will not be able to arbitrarily flip a bit. You can set a bit, but if that bit is already set, OR will not be able to clear it.
You absolutely cannot since the negative is the two's complements of the original one. So even if it is true that in a negative number the MSB is 1 is not enought to put a 1 that bit to obtain the negative. You must negate all the bits and add one.
You can give a try simpler way changeTime = changeTime >= 0 ? changeTime : -(changeTime);

Why does the F# Bitwise Operator pad with 1's for signed types?

I was looking at F# doc on bitwise ops:
Bitwise right-shift operator. The
result is the first operand with bits
shifted right by the number of bits in
the second operand. Bits shifted off
the least significant position are not
rotated into the most significant
position. For unsigned types, the most
significant bits are padded with
zeros. For signed types, the most
significant bits are padded with ones.
The type of the second argument is
int32.
What was the motivation behind this design choice comparing to C++ language (and probably C too) where MSB are padded with zeros? E.g:
int mask = -2147483648 >> 1; // C++ code
where -2147483648 =
10000000 00000000 00000000 00000000
and mask is equal to 1073741824
where 1073741824 =
01000000 00000000 00000000 00000000
Now if you write same code in F# (or C#), this will indeed pad MSB with ones and you'll get -1073741824.
where -1073741824 =
11000000 00000000 00000000 00000000
The signed shift has the nice property that shifting x right by n corresponds to floor(x/2n).
On .NET, there are CIL opcodes for both types of operations (shr to do a signed shift and shr.un to do an unsigned shift). F# and C# choose which opcode to use based on the signedness of the type which is being shifted. This means that if you want the other behavior, you just need to perform a numeric conversion before and after shifting (which actually has no runtime impact due to how numbers are stored on the CLR - an int32 on the stack is indistinguishable from a uint32).
To answer the reformed question (in the comments):
The C and C++ standards do not define the result of right-shifting a negative value (it's either implementation-defined, or undefined, I can't remember which).
This is because the standard was defined to reflect the lowest common denominator in terms of underlying instruction set. Enforcing a true arithmetic shift, for instance, takes several instructions if the instruction set doesn't contain an asr primitive. This is further complicated by the fact that the standard mandates either one's or two's complement representation.

Categories

Resources