8

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
  • 17,283
  • 10
  • 80
  • 136
  • 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,406
  • 5
  • 29
  • 39
Bhaskar
  • 1,028
  • 12
  • 16
  • PS: ^ is xor operator – Bhaskar Jan 21 '15 at 05:09
  • 1
    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
0

The way it works in any sane programming language (one that follows our normal order of operations) is that -1.0/3.0 is equivalent to -(1.0/3.0) which is -0.3333.... So if you want that converted to an int, it's really the cast/floor operator you need to think about, not the division. As such, if you want this behavior, you must use (int)Math.Floor(a/b), or custom code.

piojo
  • 5,701
  • 1
  • 21
  • 32
  • Thanks, I deleted that part of my answer. Some concepts I learned in computational physics have become corrupted from misuse, and recombined in ways that don't make sense. :) There rules/guidelines about which parts of operations should be cast, with the goal of losing the least information due to floating point imprecision, but I haven't really used these since university, and so have forgotten the specifics. – piojo Jan 22 '15 at 20:06
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
  • 135,435
  • 9
  • 130
  • 184
  • 1
    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