-1

My code:

int inStock = -3;
product.AVG = 0; // double
receiptIt.Quantity = 3; // int
decimal newPrice = 755.23m;
product.SPD = 79.80m; // decimal

var newAvg = (inStock * (float) product.AVG + (receiptIt.Quantity * (float) newPrice)) / (inStock + receiptIt.Quantity);
var newAvgWithSpd = newAvg + (float) product.SPD;

Why is my result in compiled program this?:

newAvg => 0
newAvgWithSpd => Infinity

But in Immediate window in Visual Studio is result as expected:

newAvg => Infinity
newAvgWithSpd => Infinity

How can this be possible in c#?:

var a = -3 * 0 + (3 * 755.23) / (-3 + 3);
var b = a + 79.80;

//Result:
a => 0; // <<=== WHY?
b => Infinity;

I can reproduce it on:

  • production server (Windows server 2016, Release build, Asp.net core 1)
  • development machine (Windows 10 64-bit, Debug build, Asp.net core 1, Debug with breakpoint )

enter image description here

But can't reproduce it on: - development machine (Windows 10 64-bit, Debug build, Asp.net core 1, Debug with Immediate Window)

enter image description here

enter image description here

EDIT: newAvg is initialized...

  • What type are newAvg and newAbgWithSpd? I vaguely remember something about floats and dividing by zero giving unexpected results, I'll try find something on it – Dave Feb 02 '18 at 13:30
  • How sure are you that the 0 in your application is the actual value, and not just the _default value for an uninitialized int_? – Flater Feb 02 '18 at 13:31
  • Visual Studio shows me newAvg and newAbgWithSpd as float. But: float / 0 = Infinity, not 0; – Hajk Hovhannisyan Feb 02 '18 at 13:32
  • @HajkHovhannisyan yeah that's true, it's very weird you see 0 in that first evaluation. – Dave Feb 02 '18 at 13:34
  • 0 is actual value. I folowed him in debug step by step. – Hajk Hovhannisyan Feb 02 '18 at 13:34
  • No, @HajkHovhannisyan -- float/0 is not *infinity*, it's error. – rory.ap Feb 02 '18 at 13:34
  • @rory.ap it is infinity see https://msdn.microsoft.com/en-us/library/system.dividebyzeroexception.aspx – Dave Feb 02 '18 at 13:35
  • 1f/0 = Infinity // Tested in Immediate Window – Hajk Hovhannisyan Feb 02 '18 at 13:36
  • How are you reproducing this in production? Where is this value appearing? – Rob Feb 02 '18 at 13:38
  • Not related to your question, but never assign `double` number to `decimal` like that `decimal newPrice = 755.23;`. Always use `decimal` literals `decimal newPrice = 755.23M;`. – Racil Hilan Feb 02 '18 at 13:39
  • @Dave -- interesting. Why in the world would that be, when everywhere else on earth divide by zero is error. – rory.ap Feb 02 '18 at 13:39
  • 1
    @rory.ap on the contrary, everywhere in the world dividing a floating point number by 0 returns ∞. It's [the standard](https://en.wikipedia.org/wiki/IEEE_754-1985). Floats *do* have Nan, positive and negative Infinity, positive and negative zero – Panagiotis Kanavos Feb 02 '18 at 13:41
  • @rory.ap Very likely they're remembering a case where the denominator was a number extremely close to zero, but not quite. – Rob Feb 02 '18 at 13:41
  • @rory.ap Because that's according to the rules of IEEE 754 arithmetic. Floating numbers (`double` and `float` in C#) are not precise numbers. So a value like zero is not exactly zero. – Racil Hilan Feb 02 '18 at 13:41
  • @RacilHilan Thank you. This assignes is only for demonstration on stackowerflow. This variables are public properties in many objects; – Hajk Hovhannisyan Feb 02 '18 at 13:41
  • @PanagiotisKanavos Everywhere in the world? What about mathematics, where's it's typically undefined? – Rob Feb 02 '18 at 13:42
  • 1
    @Rob mathematics don't use floating point numbers. When they do, as in DSP algorithms, they use the IEEE standard – Panagiotis Kanavos Feb 02 '18 at 13:42
  • @PanagiotisKanavos Well, yes, now with your edited comment ;) – Rob Feb 02 '18 at 13:43
  • @Rob this is a question about C# and floating point numbers, not mathematics – Panagiotis Kanavos Feb 02 '18 at 13:43
  • @Rob I have test in code on production: float.IsNaN(newAvg) || float.IsInfinity(newAvg) and it never identified Infinity value **newAvg** on production . – Hajk Hovhannisyan Feb 02 '18 at 13:45
  • 1
    @HajkHovhannisyan no repro on a .NET Core console app either in Debug or Release. Both numbers are Infinity. Did you try this on a console application with *variables*, not properties? Perhaps a getter or setter is modifying the value or casting it? – Panagiotis Kanavos Feb 02 '18 at 13:51
  • @PanagiotisKanavos What version of .NEt core are you used? – Hajk Hovhannisyan Feb 02 '18 at 13:53
  • @PanagiotisKanavos Getters and setters is only short variant without body. No casting... – Hajk Hovhannisyan Feb 02 '18 at 13:54
  • @HajkHovhannisyan I get infinity in 1.0 and 2.0. Try a console application with variables – Panagiotis Kanavos Feb 02 '18 at 13:55
  • 1
    Could this be floating point precision rearing it's head. You thinking you are dividing by 0 but actually you are dividing by 0.000000000001 or something silly and hence you don't get infinity you get 0 ? – Dave Feb 02 '18 at 13:55
  • @PanagiotisKanavos Oh... Where is problem? I have not any idea for debug or resolve this absurd arithmetic behavior... – Hajk Hovhannisyan Feb 02 '18 at 13:57
  • @Dave I tried to cast newAvg to double and decimal in ImmediateWindow and result is still 0. But good point. Thank you :) – Hajk Hovhannisyan Feb 02 '18 at 14:00
  • @DirkVollmar I checked all values in Visual Studio at break point memory viewer and Watch Window – Hajk Hovhannisyan Feb 02 '18 at 14:03
  • Have you read the article [Division By Zero Doesn't Always Raise An Exception](https://www.codeproject.com/Tips/579137/Division-By-Zero-Doesnt-Always-Raise-An-Exception)? – Jonathan Wood Feb 02 '18 at 14:03
  • @JonathanWood Yeah but my error is still strange. 3f/0 = Infinity. But my code work like: 3f/0 = 0 – Hajk Hovhannisyan Feb 02 '18 at 14:06
  • 3
    @HajkHovhannisyan: Are you sure you are showing your actual code here? `decimal newPrice = 755.23;` does not even compile giving `Error CS0664 Literal of type double cannot be implicitly converted to type 'decimal'; use an 'M' suffix to create a literal of this type` – Dirk Vollmar Feb 02 '18 at 14:12
  • @DirkVollmar This assignes is only for demonstration on stackowerflow. This variables are public properties in many objects – Hajk Hovhannisyan Feb 02 '18 at 14:20
  • 4
    @HajkHovhannisyan If the code shown in your question isn't the actual code used and doesn't demonstrate your issue, then you haven't created a proper [MCVE] – mason Feb 02 '18 at 14:21
  • @mason It **IS** complete, but i can't write here all library classes... Served code is minimal and complete. Typo is repaired. – Hajk Hovhannisyan Feb 02 '18 at 14:25
  • 1
    It gives back **+Infinity** for both *newAvg* and *newAvgWithSpd*. – Igor Dimchevski Feb 02 '18 at 14:29
  • 3
    @HajkHovhannisyan So you're telling us that you cannot reproduce the error with the code you have in this question, because it is related to a bunch of other libraries? And someone should thus be able to guess why you are getting an error? That is not the definition of Complete. – default Feb 02 '18 at 14:30
  • @Default No. I posted code with algorithm and verified variables from VS breakpoint memory viewer. That **IS** all necessary context for problem. My mistake is only typo in variable declarations. – Hajk Hovhannisyan Feb 02 '18 at 14:37
  • 1
    Likely the tooltip you see isn't refreshed. Check in your code whether `double.IsPositiveInfinity(newAvg)` evaluates to true. – Dirk Vollmar Feb 02 '18 at 14:38
  • 1
    When you are testing it with breakpoint on, are you only looking at the tooltip like display - to say that it is wrong? (My guess is that tooltip comes from ReSharper, does it not - maybe there is an error in ReSharper) Try to add the value to watch window, does it display the correct value? – Rand Random Feb 02 '18 at 14:44
  • 3
    In your screenshot we can see that you set `newAvg = 0` if it is infinity... right after that telemetry thing... – Dirk Vollmar Feb 02 '18 at 14:45
  • see the answer here: https://stackoverflow.com/questions/4262286/why-does-c-sharp-allow-dividing-a-non-zero-number-by-zero-in-floating-point-type – Juergen Gutsch Feb 02 '18 at 14:53
  • @HajkHovhannisyan: See this: https://i.stack.imgur.com/Bmjpb.png This shows why it is important to create a [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve). – Dirk Vollmar Feb 02 '18 at 14:53
  • @DirkVollmar newAvg = 0 is never assigned. IsInfinity() allways return false. – Hajk Hovhannisyan Feb 02 '18 at 15:03
  • 1
    Can you create us an MVCE so that we can repro? – Dirk Vollmar Feb 02 '18 at 15:07

1 Answers1

1

I suspect that you have set a breakpoint on the var newAvg = .. line and that you see the value of newAvg before it has been assigned the new calculated result, i.e. Infinity. How else could newAvgWithSpd on the next line become Infinity since it is newAvg + 79.80f?

UPDATE

The code context mentioned in your comment has the lines

if(float.IsNaN(newAvg) || float(IsInfinity(newAvg))
{
    _telemetry.TrackTrace(...);
    newAvg = 0;
}

Your breakpoint is set after these lines. This explains why newAvg == 0.

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
  • 1
    If that's the case, then this is not a worthy answer (a comment at best) and the question must be closed as off-topic. 57k+ shouldn't need to be told that. – Racil Hilan Feb 02 '18 at 14:35
  • No. That is not that case. Current statement is below. I can show you on picture. – Hajk Hovhannisyan Feb 02 '18 at 14:40
  • 2
    If my statement is a solution, it should be an answer. Whether the question has to be closed it another question. – Olivier Jacot-Descombes Feb 02 '18 at 14:42
  • 1
    @DirkVollmar I'm not aggressive. I didn't say this answer was wrong or didn't explain what's going on. I said that if the issue was as described in this answer, then the question is off-topic and should be closed, not answered. Telling the OP that you see an early value so wait for the next line is not a programming answer, it's a comment. And it is based on speculation (it starts with **I suspect**) that could be right or wrong. – Racil Hilan Feb 02 '18 at 14:45
  • I uploaded new screenshot with actual breakpoit and context. variable newAvg **IS** initialized. – Hajk Hovhannisyan Feb 02 '18 at 14:46
  • 1
    @HajkHovhannisyan: In this case I would follow @DirkVollmar's advice and add code to test the value `if (double.IsPositiveInfinity(newAvg)) {...}`. – Olivier Jacot-Descombes Feb 02 '18 at 14:46
  • This is my code context. I already used IsInfinity() function. But it is only workaround: https://i.stack.imgur.com/R4n4Z.png – Hajk Hovhannisyan Feb 02 '18 at 14:50
  • Nono... It never evaluate IsInfinity(newAvg) as true. newAvg = 0 are never assigned. – Hajk Hovhannisyan Feb 02 '18 at 15:00
  • *If my statement is a solution, it should be an answer. Whether the question has to be closed it another question.*. Well, a question that should be closed is a question that should **NOT** be answered, so it's not *another question*. And how come your *statement is a solution*? Solution for what exactly? What problem does it solve? A problem that doesn't exist (your answer clearly says that the OP's problem doesn't exist and he's just seeing an early value). See what experts like Jon Skeet and Dirk do. – Racil Hilan Feb 02 '18 at 15:01
  • 1
    @RacilHilan: Whether a question must be closed or not often depends on the answers given. Now it seems to turn out that it was a logical programming error and that the right answer could indeed be a programming answer. Therefore, am reluctant to close questions prematurely. – Olivier Jacot-Descombes Feb 02 '18 at 15:04
  • 1
    There is nothing such as closing *questions prematurely*, and it has nothing to do with the answers. We close questions based on the details in the question at the moment, period. No other factor is considered (Or at least, this is how it should be, but we cannot force everybody to follow the rules). Now, if the OP adds more details to the question that changes the situation, then the question can be reopened. Please read the rules. You clearly answered based on speculations and the answer was not worthy of being an answer, and you keep speculating and updating it. This should be in comments. – Racil Hilan Feb 02 '18 at 15:12
  • 1
    Do note that typographical errors *also* constitutes as an off topic close reason. – default Feb 02 '18 at 15:14
  • Hmmm... maybe It can be answer. It's possible to be my mistake in debugging. I created testing project and can't reproduce too. I'm closing this question. If problem still preserve, then i can post better documented question. – Hajk Hovhannisyan Feb 02 '18 at 15:49
  • Thank you all :) – Hajk Hovhannisyan Feb 02 '18 at 15:50
  • He probably meant `accept`. – Olivier Jacot-Descombes Feb 02 '18 at 16:40
  • 1
    Yes i mean accept. :) – Hajk Hovhannisyan Feb 02 '18 at 16:43