Подтвердить что ты не робот

Как найти следующий кратный 10 из любого целого?

Динамическое целое число будет любым числом от 0 до 150.

то есть. - возвращает число 41, нужно вернуть 50. Если число равно 10, нужно возвратить 10. Число 1 нужно вернуть 10.

Думал, что могу использовать функцию потолка, если я изменяю целое число как десятичное...? затем используйте функцию потолка и верните ее в десятичную точку?
Остается только знать, является ли число 1, 2 или 3 цифры (то есть - 7 против 94 против 136)

Есть ли лучший способ достичь этого?

Спасибо,

4b9b3361

Ответ 1

n + (10 - n % 10)

Как это работает. Оператор% вычисляет остальную часть деления (поэтому 41 % 10 оценивается до 1, а 45 % 10 оценивается до 5). Вычитая, что из 10 оценивает, сколько вам нужно, чтобы достигнуть следующего кратного.

Единственная проблема заключается в том, что это превратится в 40 в 50. Если вы этого не хотите, вам нужно будет добавить проверку, чтобы убедиться, что она уже не кратна 10.

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

Ответ 2

Вы можете сделать это, выполнив целочисленное деление на 10 округление, а затем умножив результат на 10.

Чтобы разделить A на B округление, добавьте B - 1 в A, а затем разделите его на B с помощью "обычного" целочисленного деления

Q = (A + B - 1) / B 

Итак, для вашей конкретной проблемы все вместе будет выглядеть следующим образом

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);

P.S. Я не знаю, нужно ли вам это расширить до отрицательных чисел. Если вы это сделаете, следует позаботиться о том, чтобы сделать это правильно, в зависимости от того, что вам нужно в результате.

Ответ 3

Как насчет ((n + 9) / 10) * 10?

Выход 0 = > 0, 1 = > 10, 8 = > 10, 29 = > 30, 30 = > 30, 31 = > 40

Ответ 4

Как насчет использования целочисленной математики:

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

Ответ 5

tl; dr: ((n + 9) / 10) * 10 компилируется в самый лучший (самый быстрый) код asm в большинстве случаев, и его легко читать и понимать для людей, которые знают, что такое целочисленное деление на C. Это довольно распространенная идиома.

Я не исследовал, какой лучший вариант для чего-то, что должно работать с отрицательным n, так как вы можете захотеть округлить от нуля, а не оставаться в направлении + бесконечности, в зависимости от приложения.


Глядя на операции C, используемые различными предложениями, самым легким является Марк Дикинсон (в комментариях):

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

Он выглядит более эффективным, чем простое разделение/умножение, предложенное несколькими людьми (в том числе @bta): ((n + 9) / 10) * 10, потому что у него просто есть добавление, а не умножение. (n+9 - общее подвыражение, которое нужно вычислять только один раз.)

Оказывается, что оба компилируются в буквально идентичный код, используя трюк компилятора преобразования деления на константу в умножить и сдвинуть, см. этот Q & A для того, как он работает. В отличие от аппаратной команды div, которая стоит того же, независимо от того, используете ли вы результат quotient, остаток или оба результата, метод mul/shift делает дополнительные шаги для получения остатка. Таким образом, компилятор видит, что он может получить тот же результат от более дешевого вычисления и заканчивает компиляцию обеих функций в один и тот же код.

Это верно для x86, ppc и ARM, а также для всех других архитектур, которые я просмотрел в проводнике компилятора Godbolt. В первой версии этого ответа я увидел sdiv для %10 для Godbolt gcc4.8 для ARM64, но он больше не установлен (возможно, потому, что он был неправильно сконфигурирован?) ARM64 gcc5.4 этого не делает.

В Godbolt установлен MSVC (CL), и некоторые из этих функций компилируются по-разному, но я не нашел времени, чтобы лучше понять, какая компиляция.


Обратите внимание, что в выводе gcc для x86 умножить на 10 выполняется дешево с lea eax, [rdx + rdx*4], чтобы сделать n * 5, затем add eax,eax, чтобы удвоить это. imul eax, edx, 10 будет иметь задержку на 1 цикл выше на Intel Haswell, но будет короче (на один уровень меньше). gcc/clang не используют его даже с -Os -mtune=haswell:/


Принятый ответ (n + 10 - n % 10) еще дешевле вычислять: n+10 может происходить параллельно с n%10, поэтому цепочка зависимостей на один шаг короче. Он компилируется с меньшим количеством инструкций.

Однако он дает неправильный ответ для кратных 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) работает "правильно" для отрицательных целых чисел, округляя до + бесконечности, но намного дороже вычислять. Он требует двух модульных операций, поэтому он по существу вдвое дороже. Он компилирует примерно в два раза больше инструкций x86, делая примерно в два раза больше работы других выражений.

Программа для печати результатов (такая же, как ссылки на боксбол)

#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));
}

Ответ 6

в C, однострочный:

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

Ответ 7

Помните, что ответы, основанные на операторах div и mod ( "/" и "%" ), не будут работать для отрицательных чисел без if-теста, потому что C и С++ неправильно реализуют эти операторы для отрицательных чисел. (-3 mod 5) равно 2, но C и С++ вычисляют (-3% 5) как -3.

Вы можете определить свои собственные функции div и mod. Например,

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

Ответ 8

Вы можете сделать число mod 10. Затем возьмите этот результат, вычтите его из десяти. Затем добавьте этот результат в оригинал.

if N%10 != 0  #added to account for multiples of ten 
  a=N%10
  N+=10-a

Ответ 9

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

Ответ 10

int n,res;
...

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

или

res = (n / 10)*10 + ((n % 10) ? 10:0);

Ответ 11

В псевдокоде:

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)

Ответ 12

round_up(int i) 
{
      while(i%10) {
            i++;
      }
      return(i);
}