Spot the defect: rounding, part two

Last time I challenged you to find a value which does not round correctly using the algorithm

Math.Floor(value + 0.5)

The value which does not round correctly is the double 0.49999999999999994, which is the largest double that is smaller than 0.5. With the given algorithm this rounds up to 1.0, even though clearly 0.49999999999999994 is less than one half, and therefore should round down.

What the heck is going on here?

Continue reading

Spot the defect: rounding

The intention of this method is to round a double to the nearest integer. If the double is exactly half way between two integers then it rounds to the larger of the two possibilities:1

static double MyRound(double d)
{
  return Math.Floor(d + 0.5);
}

Is it correct? Can you find a value for which it does not give the mathematically correct value?2

UPDATE: The answer is in the comments, so if you don't want spoilers, don't read the comments.

Next time on FAIC: The answer, of course.

  1. For negative numbers, -1.5 should round to -1.0, since -1.0 is larger than -2.0; I do not mean larger in the sense of absolute magnitude. That would be characterized as "midpoint rounding away from zero".
  2. HINT: The value I'm thinking of is small.

Defect spotting, part two

I had a great time hanging out with my colleagues Bob and Amie yesterday at the HUB, talking with students, spotting defects and handing out yo-yos. Thanks to all who came out, and to the SWE for putting on a great event.

To follow up on the puzzle I posted yesterday: the terrible flaw, which most people spotted right away, was that the expression geteuid != 0 was of course intended to be geteuid() != 0. The code as written compares the function pointer to null, which it never is, and therefore the right side is always true, and therefore the conditional falls into the "fail with an error" branch more often than it ought to. The program succeeds if the user really is root, or if they are "sudo" root. It is intended to succeed also if the user is "effectively" root, but it does not. Thank goodness in this case the program fails to a secure mode! It is not at all difficult to imagine a situation where such an accidental function pointer usage causes the program to fail into the insecure mode. In any event, Coverity's checker catches this one. (And of course more modern languages like C# do not allow you to use methods in a context other than a call or delegate conversion.)

There are of course any number of other flaws in this fragment. First, it's now considered bad form to check for root like this; rather, check to see if the user is granted an appropriate permission. Second, the code is hard to read if you do not know the convention that the root user gets magical id zero by default; the code could be much more self-documenting. And so on; several people made good observations in the comments.


Next time on FAIC: You can build a hollow house out of solid bricks, and you can build a deadlocking program out of threadsafe methods too.

Nullable micro-optimizations, part seven

Today, a puzzle for you.

We've been talking about how the Roslyn C# compiler aggressively optimizes nested lifted unary operators and conversions by using a clever technique. The compiler realizes the inner operation as a conditional expression with a non-null nullable value on the consequence branch and a null nullable value on the alternative branch, distributes the outer operation to each branch, and then optimizes the branches independently. That then gives a conditional expression that can itself be the target of further optimizations if the nesting is deeper.

This works great for lifted conversions and unary operators. Does it also work for binary operators? It seems like it would be a lot harder to make this optimization work for a lifted binary operator where both operands are themselves lifted operations. But what if just one of the operands was a lifted operation, and the other operand was guaranteed to be non-null? There might be an opportunity to optimize such an expression. Let's try it. Suppose X() and Y() are expressions of type int? and that Z() is an expression of type int:

int? r = X() * Y() + Z();

We know from our previous episodes that operator overload resolution is going to choose lifted multiplication for the inner subexpression, and lifted addition for the outer subexpression. We know that the right operand of the lifted addition will be treated as though it was new int?(Z()), but we can optimize away the unnecessary conversion to int?. So the question is can the C# compiler legally code-generate that as though the user had written:

int? r;
int? tempX = X();
int? tempY = Y();
int tempZ = Z();
r = tempX.HasValue & tempY.HasValue ?
  new int?(tempX.GetValueOrDefault() * tempY.GetValueOrDefault() + tempZ) :
  new int?();

If you think the answer is "yes" then the follow-up question is: can the C# compiler legally make such an optimization for all nullable value types that have lifted addition and multiplication operators?

If you think the answer is "no" then the follow-up questions are: why not? and is there any scenario where this sort of optimization is valid?


Next time on FAIC we'll be kind to our fine feathered friends; after that, we'll find out the answer to today's question.


Eric is crazy busy at Coverity's head office; this posting was pre-recorded.

An "is" operator puzzle, part two

As I said last time, that was a pretty easy puzzle. The solution is: either FooBar or the type of local variable x can be a type parameter. That is:

void M<FooBar>()
{
  int x = 0;
  bool b = x is FooBar;  // legal, true if FooBar is int.
  FooBar fb = (FooBar)x; // illegal
}

or

struct FooBar { /* ... */ }
void M<X>()
{
  X x = default(X);
  bool b = x is FooBar; // legal, true if X is FooBar
  FooBar fb = (FooBar)x; // illegal
}

This not only illustrates an interesting fact about is -- that an is expression can result in true even if the corresponding cast would be illegal -- but also an interesting fact about casts. Generally speaking, a cast is allowed if the conversion either is know at compile time to always succeed, or possibly succeed. But in these cases we have a situation where the cast could possibly succeed but is still illegal. What's up with that?

There are two main factors that come to mind, based on the dual nature of casts that I've mentioned before: a cast can mean "I know that this value is of the given type, even though the compiler does not know that, the compiler should allow it", and a cast can mean "I know that this value is not of the given type; generate special-purpose, type-specific code to convert a value of one type to a value of a different type."

But neither of these things are logical when type parameters are involved. In the context of the first meaning, a cast between a type parameter and a regular type essentially means "I know that the type parameter supplied is of the given type." But in that case, why do you have a type parameter in the first place? It's like having an integer formal parameter and then asserting that it is always twelve. Why did you have the parameter at all if you know ahead of time what the argument will be?

And in the context of the second meaning, in generic code we have no way to generate the special-purpose conversion logic. Let's take our first example code, above. If FooBar is double then we have to generate different code for int-to-double than if FooBar is long. We don't have a cheap and easy way to generate that code, and if user-defined conversions are involved then we need to do overload resolution at runtime. We added that feature to C# 4; if you want to generate fresh code at runtime that can do arbitrary conversions, use dynamic.

Next time on FAIC we'll explore the question "under what circumstances will the is operator give a warning at compile time stating that the operation is unnecessary?"

An "is" operator puzzle, part one

It is possible for a program with some local variable x

bool b = x is FooBar;

to assign true to b at runtime, even though there is no conversion, implicit or explicit, from x to FooBar allowed by the compiler! That is to say that

FooBar foobar = (FooBar)x;

would not be allowed by the compiler in that same program.

Can you create a program to demonstrate this fact?

This is not a particularly hard puzzle but it does illustrate some of the subtleties of the is operator that we'll discuss in the next episode.