9

Is there an easy, efficient and correct (i.e. not involving conversions to/from double) way to do floored integer division (like e.g. Python offers) in C#.

In other words, an efficient version of the following, that does not suffer from long/double conversion losses.

(long)(Math.Floor((double) a / b))

or does one have to implement it oneself, like e.g.

static long FlooredIntDiv(long a, long b)
{
    if (a < 0)
    {
        if (b > 0)
            return (a - b + 1) / b;
        // if (a == long.MinValue && b == -1) // see *) below
        //    throw new OverflowException();
    }
    else if (a > 0)
    {
        if (b < 0)
            return (a - b - 1) / b;
    }
    return a / b;
}

*) Although the C# 4 spec of the Division operator leaves it open whether OverflowException is raised inside unchecked, in reality it does throw (on my system) and the Visual Studio .NET 2003 version even mandated it throw:

If the left operand is the smallest representable int or long value and the right operand is –1, [..] System.OverflowException is always thrown in this situation, regardless of whether the operation occurs in a checked or an unchecked context.

Edit

The crossed out statements about checked and unchecked are all nice and well, but checked is in fact only a compile time concept, so whether my function should wrap around or throw is up to me anyway, regardless of whether code calling the function is inside checked or not.

Community
  • 1
  • 1
Evgeniy Berezovsky
  • 18,571
  • 13
  • 82
  • 156
  • 1
    You mean, an alternative to just passing the result into `Math.Floor`? – Pierre-Luc Pineault Jan 21 '15 at 04:38
  • Integer division is already doing that, not literally calling `Math.Floor`, but result is the same, it cuts off whole decimal part. `Math.Floor` is redundant in this case. – Marko Gresak Jan 21 '15 at 04:39
  • 1
    @maremp: only for positive results. See the OP's table for examples of "floor" negative results that are different from the C# `/` operator implementation. – Peter Duniho Jan 21 '15 at 04:40
  • Oh yeah @PeterDuniho, I forgot about that... – Marko Gresak Jan 21 '15 at 04:45
  • 2
    Not a solution, but I believe your code might fail in some corner cases. `var a = long.MinValue; var b = -1L;` OR `var a = long.MaxValue; var b = -1L;`. – publicgk Jan 21 '15 at 05:40

3 Answers3

3

You can try this:

if (((a < 0) ^ (b < 0)) && (a % b != 0))
{
   return (a/b - 1);
}
else
{
   return (a/b);
}

Edit (after some discussions in comments below):

Without using if-else, I would go like this:

return (a/b - Convert.ToInt32(((a < 0) ^ (b < 0)) && (a % b != 0)));

Note: Convert.ToIn32(bool value) also needs a jump, see implemention of the method:

return value? Boolean.True: Boolean.False;

Theoretically, it is not possible to calculate the division for a = long.MinValue and b = -1L, since the expected result is a/b = abs(long.MinValue) = long.MaxValue + 1 > long.MaxValue. (Range of long is –9,223,372,036,854,775,808 to 9,223,372,036,854,775,807.)

martijnn2008
  • 3,552
  • 5
  • 30
  • 40
Bhaskar
  • 1,028
  • 12
  • 16
  • PS: ^ is xor operator – Bhaskar Jan 21 '15 at 05:09
  • 2
    Thanks L16H7. When implementing my `FlooredIntDiv` above, I started off similar to your solution, which is as efficient, and I believe, as correct as mine (I haven't thought through whether your solution catches all the `0` corner cases), but I went the `if/else` route because I think it's easier to read. So it is equivalent to my sample implementation, but neither easier nor more efficient. – Evgeniy Berezovsky Jan 21 '15 at 05:16
  • 1
    Normally, an "efficient" formula should not use any "if" statements and the like. It should based purely on low-level arithmetic operators. – SF Lee Jan 21 '15 at 05:36
  • If I have to remove `if-else`, I would go like this: `{ return (a/b - Convert.ToInt32(((a < 0) ^ (b < 0)) && (a % b != 0))); }`. I'm using the fact that true = 1 and false = 0 when bool is converted to int. – Bhaskar Jan 21 '15 at 05:49
  • @L16H7 FYI: Your solution throws an `OverflowException` for `a = long.MinValue` and `b = -1L`. I tested it because publicgk (incorrectly) suggested my solution *might* fail for those numbers. – Evgeniy Berezovsky Jan 21 '15 at 05:52
  • It should fail since for `a = long.MinValue` and `b = -1L`, the expected result is `a/b = abs(long.MinValue) = long.MaxValue + 1`. Range of long is `–9,223,372,036,854,775,808 to 9,223,372,036,854,775,807`. Does your program give the correct result? @EugeneBeresovsky – Bhaskar Jan 21 '15 at 05:57
  • Put a limit on the input. :) Case closed. @EugeneBeresovsky – Bhaskar Jan 21 '15 at 06:22
  • @L16H7 Re: correctness. I investigated a bit more, removed my previously uninformed comments and updated the question instead. – Evgeniy Berezovsky Jan 22 '15 at 02:49
  • So what do you want now? @EugeneBeresovsky. – Bhaskar Jan 22 '15 at 02:51
  • 1
    @L16H7 I was just trying to say (as my question now clarifies) - neither your nor my implementation is "incorrect" - so sorry for upsetting the applecart. I'm however still interested in any easy and efficient solution, if there is one. – Evgeniy Berezovsky Jan 22 '15 at 03:23
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/69363/discussion-between-l16h7-and-eugene-beresovsky). – Bhaskar Jan 22 '15 at 03:27
  • What was the outcome? I'm interested too. The link to the chat does not work. – alelom Nov 16 '21 at 19:01
  • There may be no if-elses, but wouldn't using `&&` cause branching due to short-circuit logic? (branching when the left hand side is false) Using `&` would prevent short circuiting. – trigger_segfault Aug 27 '23 at 17:29
0

You don't need to implement this yourself, the Math class provides a builtin method for doing Euclidean division: Math.DivRem()

The only downside is that you have to provide an assignable variable for the remainder:

long remainder;
long quotient = Math.DivRem(a, b, out remainder);
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
  • 2
    The return value of `Math.DivRem` is the same as `a / b`, so calling `Math.DivRem` is not necessary. As to what's wrong with `a / b`: It does not give the floored result if a or b are negative. – Evgeniy Berezovsky Nov 15 '18 at 23:40
0

If both arguments a and b are long (or any other integer type)

long c = a/b;

is giving a floor integer division in C# just like in Python. Nothing to convert to anything. It is even using a proper integer operation on the processor level.

All operations in C# are executed based on their types.

  • Integer division rounds towards zero, so if a or b are negative the result will be rounded up instead of down. – Tim Styles Jul 05 '23 at 16:51