Округление целых чисел до ближайших десяти или сотен в C

Я пытаюсь придумать функцию в C, которая удовлетворяла бы следующим условиям:

  • Он принимает целое число больше 0 в качестве аргумента;
  • Он округляет это целое число до ближайшего значения, чтобы только первая цифра не была нулем.

Например:

53 получается 60..

197 выходит как 200..

4937 получается 5000..

Есть ли способ сделать это, чтобы требование выполнялось независимо от количества нулей в конце?

Например, я понимаю, как я мог бы сделать это в каждом отдельном случае. divide 53 by 10 then ceil(), multiply by 10, но мне нужен такой, который может обрабатывать любые значения.

Мнения? Идеи?


person M. Ryan    schedule 15.01.2013    source источник
comment
проанализируйте int как строку, разделите int на 10 * (длина строки минус 1), заполните его и умножьте на свой делитель. Будет ли это работать?   -  person Tebc    schedule 15.01.2013
comment
На самом деле я имел в виду мощность, а не умножение, но я буду голосовать за решение журнала.   -  person Tebc    schedule 15.01.2013


Ответы (12)


Нет необходимости преобразовывать число в строку и обратно. Вы можете сделать это, используя базовую арифметику по модулю, а также умножение и деление.

Вот чисто числовое решение, надеюсь, несколько более эффективное с точки зрения времени выполнения:

int round_up_to_max_pow10(int n)
{
    int tmp = n;
    int i = 0;
    while ((tmp /= 10) >= 10) {
        i++;
    }

    if (n % (int)(pow(10, i + 1) + 0.5)) {
        tmp++;
    }

    for (; i >= 0; i--) {
        tmp *= 10;
    }

    return tmp;
}

printf("Original: %d; rounded: %d\n", 4937, round_up_to_max_pow10(4937));
person Community    schedule 15.01.2013
comment
+1 Согласен! Преобразование в/из строки дорого и неуклюже. Это математическая задача, и к ней следует относиться соответственно. - person Bob Kaufman; 15.01.2013
comment
Это округляет 2445 до 3000. - person Guffa; 15.01.2013
comment
@Guffa Да, как и ожидалось. - person ; 15.01.2013
comment
@Guffa - OP, к сожалению, использует круглый как синоним потолка. Последнее, по-видимому, является намерением OP. - person Bob Kaufman; 15.01.2013
comment
@Guffa Как говорит OP: это целое число вверх округляется до ближайшего значения, так что только первая цифра не равна нулю. - person ; 15.01.2013
comment
Было бы хорошо выразить код как функцию, как это было запрошено в вопросе. - person Clifford; 15.01.2013
comment
Этот код не работает, если последний элемент равен 0. Например, 4930 должно давать 5000, а не 4000. - person Pavan Yalamanchili; 16.01.2013
comment
@ H2CO3 Технически вы можете объединить две петли. Я ошибался и ошибался, пока не пришел к аналогичному решению внизу. - person Pavan Yalamanchili; 16.01.2013

Избегайте преобразования строк и циклов:

int num = ... // your number
int len = log10(num);
float div = pow(10, len);
int rounded = ceil(num / div) * div;
person rmaddy    schedule 15.01.2013

Логарифмы здесь очень полезны, чтобы дать ответ с постоянным временем на вопрос «сколько здесь нулей?»

floor(log10(x))= z //the number of zeros

возьмет основание логарифма 10 и даст вам количество нулей, которые будут в x.

Затем вы можете использовать случайную идиому C

(A+B-1)/B

чтобы быстро найти потолок A/B, что приводит к правильной первой цифре следующим образом:

zeros = exp10(1,z);
((x+zeros-1)/zeros) * zeros

Это псевдокод, но вы должны уловить идею. Ключевое понимание состоит в том, что логарифмы — это способ математически определить, сколько цифр в числе.

person argentage    schedule 15.01.2013

API какао:

int number=9435;
NSString *string=[NSString stringWithFormat:@"%d",number];
long length=[string length];    
NSString *roundedString=[NSString stringWithFormat:@"%d",([[string substringToIndex:1]intValue]+1)];
while (--length>0) {
    roundedString=[roundedString stringByAppendingString:@"0"];
}
int roundedNumber=[roundedString intValue];
NSLog(@"%d,   %d",number,roundedNumber);

По типичному стилю C математически:

int i=8517;

int temp=i;
int len,msb;

for (len=0; temp>0; len++) {
    msb=temp;
    temp/=10;
}
msb++;
int multiplier=1;
for (int i=1; i<len; i++) {
    multiplier*=10;
}
 NSLog(@"Rounded : %d",msb*multiplier);
person Anoop Vaidya    schedule 15.01.2013
comment
Я видел десятки ответов, и даже я могу решить эту школьную проблему для младших классов, мне очень хотелось решить это ... однако, используя несколько API-интерфейсов какао, это можно было бы решить очень легко .... : D - person Anoop Vaidya; 15.01.2013
comment
Слишком поздно, но добавил еще один способ, используя какао-нити - person Anoop Vaidya; 16.01.2013
comment
Не думаю, что это хорошая реклама Cocoa или Objective-C ;-) Нечитабельно. И вопрос отмечен тегом C. - person Clifford; 16.01.2013
comment
@Clifford: он отредактировал вопрос, ранее он был помечен как ios, какао, obj-c. - person Anoop Vaidya; 16.01.2013
comment
@AnoopVaidya: Мои извинения. - person Clifford; 16.01.2013

Я не уверен, хотите ли вы круглый или ceil. Но поведение, которое вы показываете в вопросе, предполагает ceil. Так что я включил это.

int my_ceil(int num)
{
    int den = 1;
    int inc = 0;

    while (num >= 10) {
        inc += num % 10;
        num /= 10;
        den *= 10;
    }

    return (num + (inc > 0)) * den;
}

ИЗМЕНИТЬ

Изменен код для удаления ceil и других лишних операций.

ИЗМЕНИТЬ 2

Фиксировано для кратных 10.

person Pavan Yalamanchili    schedule 15.01.2013
comment
Не работает для некоторых номеров. Если число равно 9, результат равен 10, если число равно 10, результат равен 11... - person Guffa; 15.01.2013
comment
@Guffa Вы правы, это не сработает для чисел, кратных 10. Думаю, теперь я исправил. - person Pavan Yalamanchili; 15.01.2013
comment
@Guffa Он производил 10, а не 180. Пропустил скобки. - person Pavan Yalamanchili; 16.01.2013
comment
Работает, но требует компиляции C99 или C++ из-за размещения объявлений. - person Clifford; 16.01.2013
comment
Старые привычки @Clifford :). Удаление условия if должно исправить ситуацию. Это не является строго необходимым. - person Pavan Yalamanchili; 16.01.2013
comment
@Pavan: Код был в порядке, я просто сделал заметку для тех, кто использует компиляцию C в Visual C++. - person Clifford; 16.01.2013
comment
@Clifford В любом случае спасибо за указание. Я смог удалить дополнительную строку кода, потому что оглянулся на нее. - person Pavan Yalamanchili; 16.01.2013

Попробуйте взять первый символ введенного числа, добавить 1, а затем добавить нули.

    Dim Input = "23568"
    Dim roundUp = Left(Input, 1) + 1

    For x = 1 To Len(Input) - 1
        roundUp &= "0"
    Next

В VB, но, надеюсь, вы поняли идею.

person Brian Salta    schedule 15.01.2013
comment
Это помечено C, а не VB. - person rmaddy; 15.01.2013
comment
Поэтому я написал В VB, но, надеюсь, вы поняли. Концепция все еще применяется. - person Brian Salta; 15.01.2013
comment
Если на входе было 200, на выходе будет 300, хотя должно быть 200. - person Clifford; 16.01.2013

Я бы преобразовал число в строку. Получить длину строки.

Потом:

// pseudo code:
divisor = pow(10, len of number string)
answer = ceil (number/divisor) * divisor;
person Satish    schedule 15.01.2013
comment
Синтаксис не в порядке, но он выражает концепцию. +1. - person Ramy Al Zuhouri; 15.01.2013
comment
Математически количество десятичных цифр равно floor(log10(n) + 1)) или, проще говоря, (int)(log10(m) + 1) - преобразование строки не требуется. - person Clifford; 15.01.2013

Вы можете делить число на десять, пока не останется только одна цифра, а затем умножить его обратно на размер:

int n = 4937;

int m = 1;
while (n >= 10) {
  n = (n + 9) / 10;
  m *= 10;
}
n *= m;
person Guffa    schedule 15.01.2013

Это должно сделать это:

static int
rnd_up(int val)
{
    double e, r;

    e = exp10(trunc(log10((double)val)));
    r = round(((double)val / e) + 0.5);

    return(r * e);
}
person Lee-Man    schedule 15.01.2013
comment
Возможно, стоит отметить, что exp10(n) является расширением библиотеки GNU, эквивалентным pow(10,n). - person Clifford; 15.01.2013
comment
trunc() и round() тоже не стандартные - person Clifford; 16.01.2013
comment
Скомпилировано на стандартном Linux с использованием _GNU_SOURCE и math.h. Я не видел просьбы решить проблему с каким-то конкретным подмножеством того. - person Lee-Man; 16.01.2013
comment
На самом деле, я просто высказал мысль для тех, кому это важно. В этом случае я протестировал многие из более рационально выглядящих опубликованных решений, но ваше я не смог протестировать с помощью VC++. Я бы воспринял отсутствие целевой спецификации как подразумевающее необходимость как можно более широкой применимости, а не мандат на сужение решения. - person Clifford; 16.01.2013
comment
Моей целью не было решить собственно проблему компиляции кода, поэтому я не предоставил всю программу, хотя она у меня была. Моя цель состояла в том, чтобы показать, что математика довольно проста и что ее можно выполнить, например, в стандартной системе Linux. - person Lee-Man; 16.01.2013

Нет петель.

#include <math.h>
unsigned roundToNextExp10( unsigned a )
{
    int d = a ;
    if( a >= 10 )
    {
        int m ;
        d-- ;
        m = (int)pow( 10, ((int)log10(d)) ) ;
        d = (int)((d / m) + 1) * m ;
    }        
    return d ;
}
person Clifford    schedule 15.01.2013

Вот несколько советов от экспертов... Чтобы округлить число i до ближайших 10:

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

Аналогично для 100, 1000 и т. д.

person user7153622    schedule 13.11.2016

person    schedule
comment
Похоже, что это не удовлетворяет условиям, изложенным в OP. Есть ли способ сделать это, чтобы требование выполнялось независимо от количества конечных нулей? - person Brad Werth; 27.09.2014