I have 2 nullable doubles, an expected value and an actual value (let's call them value and valueExpected). A percentage is found using 100 * (value / valueExpected). However, if valueExpected is zero, it returns NaN. Everything good so far.
Now, what do I do if I need to check the value, to see if it is NaN? Normally one could use:
if (!Double.IsNaN(myDouble))
But this doesn't work with nullable values (IsNaN only works with non-nullable variables). I have changed my code to do the check (valueExpected == 0), but I'm still curious - is there any way to check for a nullable NaN?
Edit: When I say the code doesn't work, I mean it won't compile. Testing for null first doesn't work.
With all Nullable<T> instances, you first check the bool HasValue property, and then you can access the T Value property.
double? d = 0.0; // Shorthand for Nullable<double>
if (d.HasValue && !Double.IsNaN(d.Value)) {
double val = d.Value;
// val is a non-null, non-NaN double.
}
You can also use
if (!Double.IsNaN(myDouble ?? 0.0))
The value in the inner-most parenthesis is either the myDouble (with its Nullable<> wrapping removed) if that is non-null, or just 0.0 if myDouble is null. Se ?? Operator (C#).
I had the same issue and I solved it with casting the double? with double
double.IsNaN((double)myDouble)
this will return true if NaN and false if not
With C# 7.0 Pattern matching combined null + NaN check check can be written like this:
double? d = whatever;
if(d is double val && double.IsNaN(val))
Console.WriteLine(val);
The advantage is local scoped variable val at hand, which is not null, nor double.NaN and can even be used outside of if.
With pattern matching in newer Roslyn C# versions, double.NaN is a valid pattern which tests using IsNaN (that is it works differently than Equals() where NaN is never equal to NaN as specified by IEEE floating point standard).
Therefore you can now do this:
double? myDouble = something;
if (myDouble is double and not double.NaN)
Console.WriteLine("A number");
For testing NaN this can even be shortened like this:
double? myDouble = something;
if (myDouble is double.NaN)
Console.WriteLine("Not a number and not NULL");
Related
Why is SonarQube complaining about this part of the code?
I checked this code and not always this value is true.
public static void WriteJson(object value)
{
decimal decimalValue = ((decimal?)value).Value;
int intValue = (int)decimalValue;
if (decimalValue == intValue)
Console.WriteLine(intValue);
else
Console.WriteLine(decimalValue);
Console.ReadKey();
}
Why is SonarQube complaining about this?
The false positive is related to an imperfection in our dataflow analysis engine - it does not take into account the casts between floating point and integer numbers (yet) and cannot recognize when a floating point number has been truncated.
I will try to elaborate a bit: the dataflow analysis engine tracks the values of the local variables in the analyzed methods, and when a new value is being assigned to a variable, the engine creates a special object that represents the actual value. When you assign one variable to another variable, that object remains the same. For example:
var x = 5; // the symbol of x is associated with value_0
var y = x; // the symbol of y is associated with value_0
if (x == y) // value_0 is compared with value_0 --> always true
The values we assign do not contain type information (yet) and we cannot detect (yet) changes in cases like yours:
var x = 5.5; // the symbol of x is associated with value_0
var y = (int)x; // the symbol of y is associated with value_0 (wrong)
if (x == y) // false positive
and we generate false positives, but they are relatively rare, because most casts do not generate new values.
Thanks for the feedback, we will be looking into that in the near future.
Looks like SonarQube detects that you are assigning the same value to both variables, assume that value passed to method is equal to 2
1. decimal decimalValue = 2
2. int intValue = (int)decimalValue;
therefore decimalValue = 2 and intValue = 2
The C# compiler will obviously cast it to int so in case you pass 2.5 the if comparision will not evaluate always to true. But most probably SonarQube is just not aware about the casting. So it assumes always true.
I am not an expert at SonarQube, but I guess it is because SonarQube detects that you are setting intValue to the rounded form of decimalValue. And then again you are comparing decimalValue to the decimal form of intValue. So, in many cases, it will return 'true'.
To see how it will play out, suppose the decimalValue is "123.0". Then, the intValue will be exactly "123". Then, we compare "123.0"(The value of decimalValue) to "123.0"(The value of intValue after converting to decimal) with an "if" statement, which will return true. This will play out for all integers.
I have the a Convert.ToDecimal() which occasionally throws an exception with the message
Value was either too large or too small for a Decimal
, because the call to DataContainer.GetValue(ColKeyId, index) returns double.NaN.
if (Convert.ToDecimal(DataContainer.GetValue(ColKeyId, index)) != Convert.ToDecimal(newValueToSet))
{
DataContainer.SetValue(ColKeyId, index, newValueToSet);
}
I cannot change the API implementation call of the GetValue().
What would be the best approach to deal with the conversion to decimal of a NaN double?
Okay, so it sounds like you just need to detect whether or not it's a NaN value:
double value = DataContainer.GetValue(ColKeyId, index);
if (double.IsNaN(value) || double.IsInfinity(value) ||
(decimal) value != (decimal) newValueToSet)
{
DataContainer.SetValue(ColKeyId, index, newValueToSet);
}
To be honest, it's not clear why you're converting from double to decimal at all, but this code at least shows how you can detect NaN/infinite values. Note that I've changed the calls to Convert.ToDecimal to simple casts to make the code simpler - but you could use Convert.ToDecimal if you want, of course..
Decimal.TryParse
So then you will know if it converted or not and if not assigne a defasult value or branch off down some other avenue.
HTH
You can check if the value is double.NaN before setting:
if (!Double.IsNaN(DataContainer.GetValue(ColKeyId, index)))
{
if (Convert.ToDecimal(DataContainer.GetValue(ColKeyId, index)) != Convert.ToDecimal(newValueToSet))
{
DataContainer.SetValue(ColKeyId, index, newValueToSet);
}
}
What is the rational (if any) behind the following behavior:
int? a = null;
Console.WriteLine(1 > a); // prints False
Console.WriteLine(1 <= a); // prints False
Console.WriteLine(Comparer<int?>.Default.Compare(1, a)); // prints 1
Why are the comparison operators behaving differently from the default comparer for nullables?
More weirdness:
var myList = new List<int?> { 1, 2, 3, default(int?), -1 };
Console.WriteLine(myList.Min()); // prints -1 (consistent with the operators)
Console.WriteLine(myList.OrderBy(i => i).First()); // prints null (nothing) (consistent with the comparator)
Console.WriteLine(new int?[0].Min()); // prints null (nothing)
Console.WriteLine(new int[0].Min()); // throws exception (sequence contains no elements)
<= and > are lifted operators which return false if either value is null.
For the relational operators
< > <= >=
a lifted form of an operator exists if the operand types are both non-nullable value types and if the result type is bool. The lifted form is constructed by adding a single ? modifier to each operand type. The lifted operator produces the value false if one or both operands are null. Otherwise, the lifted operator unwraps the operands and applies the underlying operator to produce the bool result.
Since comparers are used for sorting they need a total ordering where null by definition compares as less than every other value. This need takes precedence over consistency with comparison operators. Returning 0 when comparing null with any other value isn't possible this that would violate transitivity, so designers had to choose to either emit an error, or sort always sort null as smaller or larger than any other value. In .net 1 they decided that null is smaller than everything else was decided in for reference types and naturally that decision carried over to nullable value types in .net 2.
The difference between these is pretty similar to how NaN behaves on floating points. For example NaN doesn't doesn't even equal itself and all comparison operators return false. But when using a comparer NaN is equal to itself and smaller than other value except null.
Enumerable.Min returns the smallest non-null value, and only returns null if the sequence contains no non-null values. With such a function null typically stands for an omitted value and you're interested in finding the smallest real value.
I have recently noticed a curiosity (at least for me). I thought that the null-coalescing operator would take the precedence over any mathematical operation but obviously i was wrong. I thought following two variables would have the same value at the end:
double? previousValue = null;
double? v1 = 1 + previousValue ?? 0;
double? v2 = 1 + (previousValue ?? 0);
But v2.Value is (the desired) 1 whereas v1.Value is still 0. Why?
Demo
v1 is 0 for the exact reason you mentioned: the null-coalescing operator actually has relatively low precedence. This table shows exactly how low.
So for the first expression, 1 + null is evaluated first, and it evaluates to a null int?, which then coalesces to 0.
v2 is saying,1 plus (if previousValue == null add to 1 the value 0,which gives 1.The
v1 is saying 1 plus null is null so lets give back the 0.
I have a custom WebControl which implements a .Value getter/setter returning a Nullable<decimal>
It's a client-side filtered textbox (a subclass of TextBox with included javascript and some server side logic for setting/getting the value)
Here is the getter & the setter from that control:
public decimal? Value
{
get
{
decimal amount = 0;
if (!decimal.TryParse(this.Text, NumberStyles.Currency, null, out amount))
{
return null;
}
else
{
return amount;
}
}
set
{
if (!value.HasValue)
{
this.Text = "";
}
else
{
this.Text = string.Format("${0:#,##0.00}", value);
}
}
}
The problem that I'm seeing is that the output from this statement:
decimal Amount = uxAmount.Value ?? 0M;
I am seeing Amount being set to "0" when uxAmount.Value returns 10000.
This worked as I expected (excuse the change in casing):
decimal? _Amount = uxAmount.Value;
decimal amount = _Amount ?? 0;
I have also seen this behaviour (recently) when calling a UDF function defined on a Linq2Sql data context along with the null coalescing operator, that is I knew my UDF call returned the expected value but I was getting the RHS value instead.
Further confusing me, if I evaluate uxAmount.Value in the watch, I get 10000 of type Nullable<decimal>.
Here are some expressions I've tried:
decimal? _Amount = uxAmount.Value; //10000
decimal amount = _Amount ?? 0; //10000
decimal amount2 = _Amount ?? 0M; //10000
decimal Amount = uxAmount.Value ?? 0M; //0
Then I added this expression following the above 4
decimal amount3 = (uxTaxAmount.Value) ?? 0M;
Now
decimal Amount = uxAmount.Value ?? 0M; //10000
decimal amount3 = (uxAmount.Value) ?? 0M; //0
It seems like the last call is always 0, but the value of uxAmount.Value (which is parsed out of .Text as per above getter/setter using a TryParse is stable. I'm stopped at a breakpoint and there's no other threads that could manipulate this value.
Note the use of the M suffix to force the constant to decimal as it was integer and I suspected a type conversion issue.
Any ideas?
The value of both the LHS and RHS appear to be stable and known.
--edit-- some screengrabs from VS2010
(This answer was constructed from my comments above.)
Are you sure the debugger dsiplays this correctly to you? Have you tried stepping some lines further down to make sure you have the updated value of amount3?
I'm sure it's just an issue with the debugger. Sometimes you have to step a little further. Maybe the translated code (IL) has some optimizations that confuse the debugger (or what would I know). But without the debugger, the value will be updated exactly when you expect it.
I've seen other experienced developers being confused by similar situations, so I know the debugger sometimes is "one line of code" behind when looking at an assignment to a local variable. Maybe someone can find a link discussing that?
Take a look at this similar question
using coalescing null operator on nullable types changes implicit type
why not just do
decimal amount = uxTaxAmount.Value.HasValue ? uxTaxAmount.Value.Value : 0M
This isn't the right answer to the original posters problems given recent edits and comments.