buq’s blog

覚えておきたいけど覚えておけなさそうなことを書きます?

整数の除算 @ C++

a/b とか a%b の挙動についてメモ. a, b の一方が負である場合は処理系依存C/C++のバージョンにもよる?)で, 多くの処理系で「実数の割り算の値a/bを0方向に丸める」ということらしい. ただし (a/b)*b + a%b == a は成り立つようになっている.

先日書いた 関数オブジェクト @ C++ - buq’s blog について考えていて気になったので.(こちらのコードも修正した)

参考 : - Integer division rounding with negatives in C++ - Stack Overflow - BohYoh.com-C/C++ FAQ 負数に対する除算の結果がおかしいのはどうしてですか。

以下実験コード

#include <iostream>
#include <iomanip>
#include <vector>
#include <numeric>
#include <algorithm>
#define range(container) container.begin(), container.end()
#define say(smth) std::cout << smth << std::endl

using namespace std;

typedef int (*func_type) (int, int);

int mymod(int a, int b){ return a%b; }            
int mydiv(int a, int b){ return a/b; }             // func. name div occupied by C language
int mynum(int a, int b){ return (a/b) * b + a%b; } // returns numerator

void show_func_result_table(const vector<int> as, const vector<int> bs, func_type f){
  cout << "b\\a|";
  for(auto && a : as) cout << setw(3) << a;
  cout << endl;
  cout << "====";
  for(auto && a : as) cout << "===";
  cout << endl;
  for(auto && b : bs){
    //if(b == 0) continue;
    cout << setw(3) << b << "|";
    for(auto && a : as) cout << setw(3) << f(a,b);
    cout << endl;
  }
}

int main(){
  const int n = 10;
  vector<int> a(n), b(n);
  //iota(a.begin(), a.end(), -4);
  iota(range(a), -4);
  auto mid_b = b.begin() + (b.end()-b.begin())/2; 
  iota(b.begin(), mid_b, -(n/2));
  iota(mid_b, b.end(), 1);

  say("a\%b");
  show_func_result_table(a, b, mymod);
  
  say("----------------------------------");
  say("a/b");
  show_func_result_table(a, b, mydiv);

  say("----------------------------------");
  say("a");
  show_func_result_table(a, b, mynum);
    
  return 0;
}

結果:

bash-3.2$ g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.4.0
Thread model: posix
bash-3.2$ g++ ./main.cpp -std=c++11 -o main.out
bash-3.2$ ./main.out 
a%b
b\a| -4 -3 -2 -1  0  1  2  3  4  5
==================================
 -5| -4 -3 -2 -1  0  1  2  3  4  0
 -4|  0 -3 -2 -1  0  1  2  3  0  1
 -3| -1  0 -2 -1  0  1  2  0  1  2
 -2|  0 -1  0 -1  0  1  0  1  0  1
 -1|  0  0  0  0  0  0  0  0  0  0
  1|  0  0  0  0  0  0  0  0  0  0
  2|  0 -1  0 -1  0  1  0  1  0  1
  3| -1  0 -2 -1  0  1  2  0  1  2
  4|  0 -3 -2 -1  0  1  2  3  0  1
  5| -4 -3 -2 -1  0  1  2  3  4  0
----------------------------------
a/b
b\a| -4 -3 -2 -1  0  1  2  3  4  5
==================================
 -5|  0  0  0  0  0  0  0  0  0 -1
 -4|  1  0  0  0  0  0  0  0 -1 -1
 -3|  1  1  0  0  0  0  0 -1 -1 -1
 -2|  2  1  1  0  0  0 -1 -1 -2 -2
 -1|  4  3  2  1  0 -1 -2 -3 -4 -5
  1| -4 -3 -2 -1  0  1  2  3  4  5
  2| -2 -1 -1  0  0  0  1  1  2  2
  3| -1 -1  0  0  0  0  0  1  1  1
  4| -1  0  0  0  0  0  0  0  1  1
  5|  0  0  0  0  0  0  0  0  0  1
----------------------------------
a
b\a| -4 -3 -2 -1  0  1  2  3  4  5
==================================
 -5| -4 -3 -2 -1  0  1  2  3  4  5
 -4| -4 -3 -2 -1  0  1  2  3  4  5
 -3| -4 -3 -2 -1  0  1  2  3  4  5
 -2| -4 -3 -2 -1  0  1  2  3  4  5
 -1| -4 -3 -2 -1  0  1  2  3  4  5
  1| -4 -3 -2 -1  0  1  2  3  4  5
  2| -4 -3 -2 -1  0  1  2  3  4  5
  3| -4 -3 -2 -1  0  1  2  3  4  5
  4| -4 -3 -2 -1  0  1  2  3  4  5
  5| -4 -3 -2 -1  0  1  2  3  4  5

-1%2は 1 になって欲しいなあ😩