Закръгляване на цели числа до най-близките десет или сто в 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, cocoa, obj-c. - person Anoop Vaidya; 16.01.2013
comment
@AnoopVaidya: Моите извинения. - person Clifford; 16.01.2013

Не съм сигурен дали искате кръгъл или таван. Но поведението, което показвате във въпроса, предполага 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
@Клифърд стари навици :). Изваждането на условието 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
Ето защо написах In 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;    

По същия начин за 100s, 1000s и т.н.

person user7153622    schedule 13.11.2016

person    schedule
comment
Изглежда, че това не отговаря на условията, посочени в OP - Има ли начин да направите това, така че изискването да бъде изпълнено, независимо от броя на нулите в края? - person Brad Werth; 27.09.2014