web-dev-qa-db-ja.com

整数の次の10の倍数を見つけるにはどうすればよいですか?

動的整数は、0〜150の任意の数値になります。

つまり、数値は41を返し、50を返す必要があります。数値が10の場合、10を返す必要があります。数値は1を返す必要があります。

整数を小数として変更すると、天井関数を使用できると考えていましたか?次に、天井関数を使用して、10進数に戻しますか?
数値だけが1桁、2桁、3桁のいずれであるかを知る必要がある(つまり、7対94対136)

これを達成するためのより良い方法はありますか?

ありがとうございました、

40
T.T.T.
n + (10 - n % 10)

これの仕組み。 %演算子は、除算の剰余(つまり41 % 10は1と評価され、45 % 10は5)と評価されます。これを10から引くと、次の倍数に到達するのに必要な量が評価されます。

唯一の問題は、これが40を50に変えることです。それが望ましくない場合は、チェックを追加して、まだ10の倍数になっていないことを確認する必要があります。

if (n % 10)
    n = n + (10 - n % 10);
84

これを行うには、10 切り上げで整数除算を実行し、結果に10を掛けます。

ABで切り上げるには、B - 1Aに変換し、「通常の」整数除算を使用してBで除算します

Q = (A + B - 1) / B 

だから、あなたの特定の問題については、whileのものは一緒に次のようになります

A = (A + 9) / 10 * 10

これは、Aを次の10の倍数に「スナップ」します。

除算とアラインメントの必要性が非常に頻繁に発生するため、通常、私のプログラムでは切り上げで[符号なし]整数を除算するためのマクロがあります。

#define UDIV_UP(a, b) (((a) + (b) - 1) / (b))

整数を次の境界に揃えるため

#define ALIGN_UP(a, b) (UDIV_UP(a, b) * (b))

上記のようになります

A = ALIGN_UP(A, 10);

追伸これを負の数に拡張する必要があるかどうかはわかりません。その場合、結果として必要なものに応じて、適切に行うように注意する必要があります。

40
AnT

((n + 9) / 10) * 10

利回り0 => 0、1 => 10、8 => 10、29 => 30、30 => 30、31 => 40

24
bta

tl; dr:_((n + 9) / 10) * 10_はより多くのケースで最も良い(最速の)asmコードにコンパイルします。 Cで整数除算が何をするかを知ってください。これはかなり一般的なイディオムです。

負のnで動作する必要があるものに最適なオプションが何であるかを調査していません。アプリケーションに応じて、+ Infinityに向かってではなく、ゼロから切り捨てたい場合があるためです。


さまざまな提案で使用されるC操作を見ると、最も軽量なのはMark Dickinsonのコメントです。

_(n+9) - ((n+9)%10)
_

(btaを含む)数人が提案する単純な除算/乗算よりも効率的に見えます:_((n + 9) / 10) * 10_。乗算の代わりに加算するだけです。 (_n+9_は、一度計算するだけでよい共通の部分式です。)

定数による除算乗算とシフト、その仕組みについてはこのQ&Aを参照 に変換するコンパイラートリックを使用して、両方が文字通り同一のコードにコンパイルされることがわかります。商、剰余、またはその両方の結果を使用しても同じコストのハードウェアdiv命令とは異なり、mul/shiftメソッドは剰余を取得するために追加の手順を実行します。そのため、コンパイラは、より安価な計算から同じ結果が得られることを確認し、両方の関数を同じコードにコンパイルします。

これは、 x86、ppc、およびARM 、およびGodboltコンパイラエクスプローラーで調べた他のすべてのアーキテクチャで当てはまります。この回答の最初のバージョンでは、ARM64用のGodboltのgcc4.8で_%10_にsdivが表示されましたが、インストールされていません(おそらく設定が間違っていたためですか?)しないで.

Godboltには現在MSVC(CL)がインストールされており、これらの関数の一部は異なる方法でコンパイルされますが、どのコンパイルがより良いかを確認する時間はありません。


X86のgcc出力では、10の乗算は _lea eax, [rdx + rdx*4]_ を使用して安価に実行され、n * 5を実行してから_add eax,eax_を実行して2倍になります。 _imul eax, edx, 10_は、Intel Haswellで1サイクル高いレイテンシを持ちますが、短くなります(1つ少ないuop)。 gcc/clangは_-Os -mtune=haswell_でも使用しません:/


受け入れられた答え(_n + 10 - n % 10_)はさらに安価に計算できます。_n+10_は_n%10_と並行して発生する可能性があるため、依存関係チェーンは1ステップ短くなります。 1つ少ない命令にコンパイルされます。

ただし、、10の倍数に対して間違った答えを与えます。 _10 -> 20_。推奨される修正では、if(n%10)を使用して、何かを行うかどうかを決定します。これはcmovにコンパイルされるため、@ Btaのコードよりも長くて悪化します。条件を使用する場合は、負の入力に対して正しい結果を得るために実行します。


これは、負の入力を含む、提案されたすべての回答の動作です:

_./a.out | awk -v fmt='\t%4s' '{ for(i=1;i<=NF;i++){ a[i]=a[i] sprintf(fmt, $i); } } END { for (i in a) print a[i]; }'
       i     -22     -21     -20     -19     -18     -12     -11     -10      -9      -8      -2      -1       0       1       2       8       9      10      11      12         18      19      20      21      22
    mark     -10     -10     -10     -10       0       0       0       0       0       0       0       0       0      10      10      10      10      10      20      20         20      20      20      30      30
    igna     -10     -10     -10       0       0       0       0       0      10      10      10      10      10      10      10      10      10      20      20      20         20      20      30      30      30
    utaal    -20     -20     -20     -10     -10     -10     -10     -10       0       0       0       0       0      10      10      10      10      10      20      20         20      20      20      30      30
     bta     -10     -10     -10     -10       0       0       0       0       0      10      10      10      10      10      10      10      10      10      20      20         20      20      20      30      30
    klatchko -10     -10     -10     -10       0       0       0       0       0       0       0       0       0      10      10      10      10      10      20      20         20      20      20      30      30
    branch   -10     -10     -20       0       0       0       0     -10      10      10      10      10       0      10      10      10      10      10      20      20         20      20      20      30      30
_

awkプログラムの転置

Ignacioのn + (((9 - (n % 10)) + 1) % 10)は、負の整数に対して「正しく」動作し、+ Infinityに向かって丸められますが、計算がはるかに高価です。 2つのモジュロ演算が必要なので、本質的に2倍の費用がかかります。 x86命令の約2倍にコンパイルされ、他の式の約2倍の作業を行います。

結果印刷プログラム(上記のゴッドボルトリンクと同じ)

_#include <stdio.h>
#include <stdlib.h>

int f_mark(int n) { return (n+9) - ((n+9)%10); }                   // good
int f_bta(int n) { return ((n + 9) / 10) * 10; }                   // compiles to literally identical code

int f_klatchko(int n) { return n + 10 - n % 10; }                  // wrong, needs a branch to avoid changing multiples of 10
int f_ignacio(int n) { return n + (((9 - (n % 10)) + 1) % 10); }   // slow, but works for negative
int roundup10_utaal(int n) {  return ((n - 1) / 10 + 1) * 10; }

int f_branch(int n) { if (n % 10) n += (10 - n % 10); return n; }  // gcc uses cmov after f_accepted code

int main(int argc, char**argv)
{
    puts("i\tmark\tigna\tutaal\tbta\tklatch\tbranch");
    for (int i=-25 ; i<25 ; i++)
    if (abs(i%10) <= 2 || 10 - abs(i%10) <= 2)  // only sample near interesting points
        printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\n", i, f_mark(i), f_accepted(i),
           f_ignacio(i), roundup10_utaal(i), f_bta(i), f_branch(i));
}
_
9
Peter Cordes

整数演算の使用はどうですか:

N=41
N+=9   // Add 9 first to ensure rounding.
N/=10  // Drops the ones place
N*=10  // Puts the ones place back with a zero
7
Harvey

in [〜#〜] c [〜#〜]one-liner

int inline roundup10(int n) {
  return ((n - 1) / 10 + 1) * 10;
}
3
Utaal

CとC++が負の数値に対して誤ってこれらの演算子を実装するため、divおよびmod演算子( "/"および "%")に基づく回答はif-testなしでは負の数値に対して機能しないことに注意してください。 (-3 mod 5)は2ですが、CとC++は-3として(-3%5)を計算します。

独自のdivおよびmod関数を定義できます。例えば、

int mod(int x, int y) {
  // Assert y > 0
  int ret = x % y;
  if(ret < 0) {
    ret += y;
  }
  return ret;
}
3
Jive Dadson

10のmodを行うことができます。そして、その結果を10から減算します。次に、その結​​果をオリジナルに追加します。

if N%10 != 0  #added to account for multiples of ten 
  a=N%10
  N+=10-a
2
Alex
int n,res;
...

res = n%10 ? n+10-(n%10) : n;

または

res = (n / 10)*10 + ((n % 10) ? 10:0);
1
Ring Ø
n + (((9 - (n % 10)) + 1) % 10)

擬似コードで:

number = number / 10
number = ceil(number)
number = number * 10

Pythonの場合:

import math
def my_func(x):
    return math.ceil(x / 10) * 10

それはそれを行う必要があります。上記のコードは、算術演算のために整数をfloat/doubleにキャストし、最後の戻り値のために整数に戻すことができることに注意してください。明示的な型キャストの例を次に示します

Python(型キャストあり):

import math
def my_func(x):
    return int(math.ceil(float(x) / 10) * 10)
0
Mike Trpcic
round_up(int i) 
{
      while(i%10) {
            i++;
      }
      return(i);
}
0
Bram