2

必要なすべての整数除算モードを実装する関数を備えたオープンソースの C または C++ ライブラリを知っている人はいますか? 考えられる行動 (肯定的な結果の場合):

round_down, round_up,
round_to_nearest_with_ties_rounding_up,
round_to_nearest_with_ties_rounding_down,
round_to_nearest_with_ties_rounding_to_even,
round_to_nearest_with_ties_rounding_to_odd

それぞれ (偶数への丸めと奇数への丸めを除く) には 2 つのバリアントがあります

// (round relative to 0; -divide(-x, y) == divide(x, y))
negative_mirrors_positive,
// (round relative to -Infinity; divide(x + C*y, y) == divide(x, y) + C)
negative_continuous_with_positive

.

私はそれを書く方法を知っていますが、確かに誰かがすでにそうしていますか?

例として、組み込みの符号付き整数除算がゼロに向かって丸められ、組み込みのモジュラスがこれと一致していると仮定すると (C++11 で一般的であり、義務付けられているように)、

int divide_rounding_up_with_negative_mirroring_positive(int dividend, int divisor) {
  // div+mod is often a single machine instruction.
  const int quotient = dividend / divisor;
  const int remainder = dividend % divisor;
  // this ?:'s condition equals whether quotient is positive,
  // but we compute it without depending on quotient for speed
  // (instruction-level parallelism with the divide).
  const int adjustment = (((dividend < 0) == (divisor < 0)) ? 1 : -1);
  if(remainder != 0) {
    return quotient + adjustment;
  }
  else {
    return quotient;
  }
}

ボーナス ポイント: 複数の引数タイプで機能します。速い; オプションでモジュラスも返します。どの引数値についてもオーバーフローしません (もちろん、0 による除算と MIN_INT/-1 を除く)。

そのようなライブラリが見つからない場合は、C++ 11 で作成してリリースし、ここの回答でリンクします。

4

1 に答える 1

1

それで、私は何かを書きました。実装は通常、見苦しいテンプレートとビット単位のコードですが、うまく機能します。使用法:

divide(dividend, divisor, rounding_strategy<...>())

rounding_strategy<round_up, negative_mirrors_positive>戦略の例はどこに ありますか。私の質問またはソースコードのバリアントのリストを参照してください。https://github.com/idupree/Lasercake/blob/ee2ce96d33cad10d376c6c5feb34805ab44862ac/data_structures/numbers.hpp#L80

C++11 [*] のみに依存し、 https://github.com/idupree/Lasercake/blob/ee2ce96d33cad10d376c6c5feb34805ab44862ac/tests/misc_utils_tests.cpp#L38で始まる単体テスト (Boost Test フレームワークを使用) を使用

これはポリモーフィックで、まともな速度であり、オーバーフローしませんが、現在モジュラスを返しません。

[*] (そして、std::make_signed と std::enable_if で置き換えるのは簡単な boost::make_signed と boost::enable_if_c と、assert() または if( で置き換えることができる caller_error_if() で。 .){throw ..} または deleted. そこにある他のものに興味がないと仮定して、残りのファイルを無視して削除できます。)

各 Division_impl のコードは、各 T を int に、T(CONSTANT) を CONSTANT に置き換えることで、C に適合させることができます。round_to_nearest_* バリアントの場合、丸めの種類をランタイム引数にするか、コードのコピーを 6 つ作成します (処理する丸めのバリエーションごとに 1 つ)。このコードは、C11 (標準ドラフト N1570 6.5.5.6) および C++11 で指定されている、一般的なゼロ方向への「/」丸めに依存しています。C89/C++98 との互換性のために、ゼロに向かって丸めることが保証されている stdlib.h div()/ldiv() を使用できます ( http://www.linuxmanpages.com/man3/div.3.phphttpを参照)。 ://en.cppreference.com/w/cpp/numeric/math/div )

于 2013-02-07T04:09:40.883 に答える