When I round off a small negative number it is rounded off to 0.
E.g: decimal.Round(-0.001M, 2) returns 0.
How can I get the sign if its rounded of to zero. Is there any other better way than to check n<0 then do the round off?
Comparing the bits works for decimal also. Thanks to #JonSkeet, else I'd have never known this trick.
var d = decimal.Round(-0.001M, 2);
bool isNegativeZero = d == decimal.Zero && decimal.GetBits(d).Last() < 0;
Here is the Demo
Is there any other better way than to check n<0 then do the round off?
The simple answer is "no". That is the most straightforward way of doing it. Unless you have a good reason to write code any more complicated than that (that you haven't mentioned in the question), don't do it. You (or another developer) will eventually come back to this code after days or months and wonder why the code was written that way.
Related
I am experiencing a division significant digit problem, but I am not sure what's the best way of fixing it.
In C#, If I do:
Math.Round(36 / 4.8)
I get 8 as expected, but if I do:
Math.Round(36 / 4.8f)
typee
I get 7 instead of 8 like I expected.
Looks like some sort of significant digit issue since 36/4.8 = 7.5 (type of double) but 36/4.8f = 7.4999995 (type of single), but I can't seem to figure out why. Is there a way to keep using float but still ensure the result gets rounded 8 correctly?
One way that I was able to to solve this issue is by rounding twice with first one specifying number of digit to round, then round that number again like:
Math.Round(Math.Round(36/4.8f, 5))
But I rather not do this kind of gymnastics if I don't have to. Is there a better to solve this issue or am I doing something wrong?
Thanks in advance
I use decimal variables in c#
I want to get Math.round(0.004449m, 2) = 0.01
I mean start rounding from the last digit ie: 9 in this example. Since Math.round(0.004449m, 5) = 0.00445 treat 0.004449m as 0.0445 at the first place.
Keep rounding. Since Math.round(0.0445m , 4) = 0.045 treat 0.0445m as 0.045
Finally Math.round(0.004449m, 2) is found to be 0.01.
I know this approach is mathematically wrong but there is also a logic behind it so my company decided to round numbers like this.
Is there this kind of function in .net?
I have a database table that needs to be converted into current form. This table has three columns that are of type Double (it's Pervasive.SQL, if anyone cares).
My problem is that this table has been around for a long time, and it's been acted upon by code going back some 15 years or better.
Historically, we have always used Double.MinValue (or whatever language equivalent at the time) to represent "blank" values provided by the user. The absence of a value, in other words, is actually stored as a value that we can recognize later and react to intelligently.
So, today my problem is that I need to loop through these records and insert them into a newly created table (this is the "conversion" I spoke of). However, I am not seeing consistent values in the tables I am converting. Here are the ones I know of for sure:
2.2250738585072014E-308
3.99285938963E-313
3.99099435427E-313
1.1125369292536007E-308
-5.389000690742776E279
2.104687961E-314
Now, I recognize that there are other ways that Double.MinValue might exist or at least be represented. Having done some google searches, I found that the first one is another representation of Double.MinValue (actually DBL_MIN referenced here: http://msdn.microsoft.com/en-us/library/6bs3y5ya(v=vs.100).aspx).
I don't want to get too long-winded, so I'll solicit questions if this is not enough information to help me. Suffice it to say, I need a reliable way of spotting all of the previous values of "minimum" and replace them with the C# Double.MinValue constant as I am looping these data rows.
If it proves to be dataRow["Value"] < someConstant, then so be it. But I'll let the math theorists help me out with that determination.
Thank you for the time.
EDIT:
Here's what I am doing with these values as I find them. It's part of a generic method that assembles values to be written to the database:
else if (c.DataType == typeof(System.Double))
{
if (inRow[c] == DBNull.Value)
retString += #"NULL";
else
{
Double d;
if (Double.TryParse(inRow[c].ToString(), out d))
retString += d.ToStringFull();
}
}
Until now, it simply accepted them. And that's bad because when the application finds them, they look like acceptable data, and not like Double.MinValue. Therefore, not seen as blanks. But that's what they are.
This is utter craziness. Let's look at some of those numbers in detail. These are all tiny numbers just barely larger than zero:
2.2250738585072014E-308
This is 1 / 21022 -- it is a normal double. This is one of the two "special" numbers in your set; it is the smallest normal double that is larger than zero. The rest of the small doubles on your list are subnormal doubles.
1.1125369292536007E-308
This is 1 / 21023 -- it is a subnormal double. This is also a special number; it is half the smallest normal double larger than zero. (I originally said that it was the largest subnormal double but of course that is not true; see the comments.)
3.99285938963E-313
This isn't anything special. It's a subnormal double equal to a fraction where the numerator is 154145 and the denominator is a rather large power of two.
3.99099435427E-313
This isn't anything special either. This time the numerator is 154073.
2.104687961E-314
This isn't anything special either. The numerator is 2129967929 and the denominator is an even larger power of two.
All the numbers so far have been very close to zero and positive. This number is very far from zero and negative, and therefore stands out:
-5.389000690742776E279
But again it is nothing special; it is nowhere even close to the negative double with the largest absolute value, which is about -1.79E308, about a billion times larger.
This is a complete mess.
My advice is stop this madness immediately. It makes absolutely no sense to use values that are incredibly close to zero to represent "blank" values; values that are incredibly close to zero should be rounded to zero, not treated as blanks!
Double already has a representative for "blank" values, namely Double.NaN -- Not A Number; it is bizarre to use a valid value to represent an invalid value when the domain already includes a specific "invalid" value. (Remember that there are actually a large number of distinct NaN bit patterns; use IsNaN to determine if a double is a NaN.)
So my advice is:
Examine individually every number in the database that is a subnormal or very small normal double. Some of those probably ought to be zero and ended up as tiny values due to rounding errors. Replace them with zero. The ones that ought to be blank, replace with database null (best practice) or double NaN (acceptable, but not as good as database null.)
Write a program to find every number in the database that is impossibly large in absolute value and replace it with database null or double NaN.
Update all clients so that they understand the convention you're using to represent blank values.
You seem to want to check if a double is really small and positive or really big, finite, and negative. (Others have detailed some problems with your approach in the comments; I'm not going to go into that here.) A test like this:
if (d == d && (d > 0 && d < 1e-290 || d < -1e270 && d + d != d))
might do roughly what you want. You'll probably need to tweak the numbers above. The d == d test is checking for NaN, while the d + d != d test is checking for infinities.
On my TI-84 Plus (Silver Edition), I can enter the following without error: (-1)^(1/3) = -1
I also know that entering some expressions like the following would yield a non-real -imaginary- number like: (-1)^.5
Now, my problem is with C#'s Math object. If I send any fractions like these: {1.667, 109.667, 0.667, 120.667} OR {4/3, 111/3, 2/3, 122/3}, I would get: {NaN, NaN, NaN, NaN}.
Do I have to write a new object MathHelper that checks the rational value and returns an answer according to a limited input switch? Or is there a feature to the Math object I am missing. I can do this on the calculator...
PS, I did not come across any similar questions online yet; so if this is a duplicate, please inform me ;)
[My new views]
Thank you all for your help! I had finished upgrading the "Microsoft.Solver.Foundation.dll" to the 4.0 targeted framework and it turned out that the 'Rational' object seemed to return only -1's and 'Indeterminate'. Then after entering (-1)^(1/2) [nonreal ans] on Google, it dawned on me that I was working with nth-roots!! So, it turned out that I had already managed imaginary numbers in the past in C#, hence having solved my problem:
Any even root 2n of a negative number -m will always equal an imaginary number i. (2n√-m)=i
I can't believe I forgot this simple algebra property
You will have to write your own Math helper to do functions like this (at least for Math.Pow). EDIT: Or you can use the Rational library like mentioned in the comments.
According to the documentation:
Input: x < 0 but not NegativeInfinity; y is not an integer, NegativeInfinity, or PositiveInfinity.
Result: NaN
Review the docs here: http://msdn.microsoft.com/en-us/library/system.math.pow.aspx
In C#, (-1)^R isn't defined for non-integer values of R.
If you try to calculate (-1)^(1/3), C# will calculate 1/3 first, resulting in a non-integer floating point number for R.
Solution:
Use the mathematical identity:
a^(x/y) = a^x * a^(1/y) x,y integers
For negative a, use:
a^1/y = -(|a|^1/y) // only works if y is odd
Or put together:
if (a < 0) {
if (y % 2 = 1) {
result = a^x * -1 * (-a)^(1.0/y); // Replace ^ with the correct C# call.
} else {
// NaN
}
} else {
result = a^(x/y);
}
Is there a shorter and better-looking alternative to
(b == 0) ? 0 : 1;
in terms of bitwise operations?
Also, to get the correct sign (-1, 0 or 1) of a given integer a I am currently using
(a > 0) ? 1 : (a >> 32);
Are there any shorter (but not slower) ways?
Personally I'd stick with the first option for your "equal to zero or not" option.
For the sign of an integer, I'd use Math.Sign and assume that the JIT compiler is going to inline it - testing that assumption with benchmarks if it turns out to be a potential bottleneck.
Think about the readability above all - your first piece of code is blindingly obvious. Your second isn't. I'm not even convinced your second piece of code works... I thought that right-shifts were effectively masked to the bottom 5 bits, assuming this is an Int32 (int).
EDIT: Just checked, and indeed your current second piece of code is equivalent to:
int y = x > 0 ? 1 : x;
The shift doesn't even end up in the compiled code.
Take this as an object lesson about caring more about micro-optimization than readability.
It's much easier to make code work if it's easy to understand. If your code gives the wrong result, I don't care how quickly it runs.
Microoptimizations are the root of all evil. You sacrifice readability for a nanosecond. That's a bad bargain
in terms of bitwise operations... Can
anyone please point that to me? Also,
to get the correct sign (-1, 0 or 1)
of a given integer a I am currently
using
(a > 0) ? 1 : (a >> 32);
Armen Tsirunyan and Jon Skeet answered your technical question, I am going to attempt to explain some technical misconceptions you appear to have.
The first mistake is that if you have a 32 bit signed integer and attempted to shift it by 32, you would be attempting to look at the 33rd bit which in the case of a signed base 2 arthmetic would be an overflow bit.
The second mistake is when you have 32-bit signed binary value. The last bit would either be a one or zero. There is a only a single zero value. So your statement of trying to figure out if the sign is ( -1,0,1) clearly indicates you don't understand this fact. If the signed bit is a 1 the number would be negative, if it was zero, it would be positive. The structures that handle a number for the most part within the .NET Framework are not aware of 2's complement and 1's complement. This of course does not mean you cannot extend that functionality or simply convert a signed integer to a 2's complement number ( really simple honestly ).
I should add that there is only one value for zero when you have a signed integer. I guess this is was my major problem with your "check the sign" statement that you made which shows a misconception about binary numbers.
http://en.wikipedia.org/wiki/Signed_magnitude#Sign-and-magnitude