C ++: Sayının en yakın katına yuvarlama


168

Tamam - temel bir soru gibi göründüğü için bunu burada yayınlamaktan utanıyorum (ve kimse kapatmak için oy verirse silerim).

Bu C ++ bir sayı katına yuvarlamak için doğru yolu mu?

Bununla ilgili başka sorular olduğunu biliyorum ama açıkça C ++ bunu yapmanın en iyi yolu nedir bilmek ilgimi çekiyor:

int roundUp(int numToRound, int multiple)
{
 if(multiple == 0)
 {
  return numToRound;
 }

 int roundDown = ( (int) (numToRound) / multiple) * multiple;
 int roundUp = roundDown + multiple; 
 int roundCalc = roundUp;
 return (roundCalc);
}

Güncelleme: Üzgünüm, niyeti açıkça belirtmedim. İşte bazı örnekler:

roundUp(7, 100)
//return 100

roundUp(117, 100)
//return 200

roundUp(477, 100)
//return 500

roundUp(1077, 100)
//return 1100

roundUp(52, 20)
//return 60

roundUp(74, 30)
//return 90

3
Mantığınızda bir hata var - diyelim ki 4'ü 2'nin en yakın katına yuvarlamak istiyorum. RoundDown = (4/2) * 2 = 4; roundUp = 4 + 2; so roundCalc = 6. Bu durumda 4 döndürmek istediğinizi varsayıyorum.
Niki Yoshiuchi

bu roundUp için çalışmaz (30,30). Cevap olarak 60 veriyor, yine de cevap olarak 30
vermeli

@bsobaid: Cevabımı en altta kontrol et. Buradaki diğer çözümlerden biraz daha basit, ancak
Niklas

3
Test vakalarınız, negatif sayıları, bölünmenin kesin olduğu vakaları, bölünmenin neredeyse kesin olduğu vakaları ve sayıların aralığın sınırlarına çok yakın olduğu örnekleri dikkat çekici bir şekilde eksik örneklerdir int.

1
Robben_Ford_Fan_boy, Aradığınız cevaba sahip düzenleme kaldırılmalıdır. Verilen cevaplardan farklıysa, kendi cevabınızı gönderebilirsiniz. Bu cevabın, cevapta ele alınması gereken problemleri vardır.
chux - Monica

Yanıtlar:


161

Bu pozitif sayılar için çalışır, negatif hakkında emin değilim. Sadece tamsayı matematik kullanır.

int roundUp(int numToRound, int multiple)
{
    if (multiple == 0)
        return numToRound;

    int remainder = numToRound % multiple;
    if (remainder == 0)
        return numToRound;

    return numToRound + multiple - remainder;
}

Düzenleme: İşte "yukarı" ile her zaman> = girdi olan bir sonuç anlamına gelirse, negatif sayılarla çalışan bir sürüm.

int roundUp(int numToRound, int multiple)
{
    if (multiple == 0)
        return numToRound;

    int remainder = abs(numToRound) % multiple;
    if (remainder == 0)
        return numToRound;

    if (numToRound < 0)
        return -(abs(numToRound) - remainder);
    else
        return numToRound + multiple - remainder;
}

+1 Bence kesinlikle en güzel ve en okunabilir çözüm.
Robben_Ford_Fan_boy

1
if(number<0){ multiple = multiple*(-1); }Negatif sayıları doğru yönde yuvarlamak için başlangıçta ekle
Josh

4
@Josh: Neden çarpma kullanılıyor? if(number<0) multiple = -multipledaha kolay.
md5

bu roundUp için çalışmaz (30,30). Cevap olarak 60 verir, yine de cevap olarak 30 vermelidir.
bsobaid

@bsobaid imkansız. if (remainder == 0)Test Bu durumda dikkatli olmalıdır. Benim için çalışıyor: ideone.com/Waol7B
Mark Ransom

115

Koşullar olmadan:

int roundUp(int numToRound, int multiple) 
{
    assert(multiple);
    return ((numToRound + multiple - 1) / multiple) * multiple;
}

Bu , negatif sayılar için sıfırdan uzaklaşmak gibi çalışır

EDIT: Negatif sayılar için de çalışan sürüm

int roundUp(int numToRound, int multiple) 
{
    assert(multiple);
    int isPositive = (int)(numToRound >= 0);
    return ((numToRound + isPositive * (multiple - 1)) / multiple) * multiple;
}

Testler


Eğer multiple2 'lik bir güç (daha hızlı ~ 3.7 kat http://quick-bench.com/sgPEZV9AUDqtx2uujRSa3-eTE80 )

int roundUp(int numToRound, int multiple) 
{
    assert(multiple && ((multiple & (multiple - 1)) == 0));
    return (numToRound + multiple - 1) & -multiple;
}

Testler


24
2 sürümün gücü için +1. Çarpma, bölme veya modulo maliyetinden tamamen kaçındığı için çok yararlıdır.
Nikos C.12

Bu algoritmaların önkoşulları olmadığından emin misiniz? Negatif sayılar ne olacak? Davranış, C ++ 11 öncesi tanımlanmamış gibi görünüyor .
cubuspl42

> Negatif sayılar ne olacak? Açıklandığı gibi, bu sıfırdan yuvarlama gibi negatif sayılar için çalışır.
KindDragon

"Yuvarlama" yı sıfırdan yuvarlama değil, pozitif sonsuza yuvarlama anlamında okudum.

8
Bunun ikinin tamamlayıcı aritmetiği ile & ~(x - 1)aynı olduğunu unutmayın & -x.
Todd Lehman

39

Faktör her zaman pozitif olacağı zaman çalışır:

int round_up(int num, int factor)
{
    return num + factor - 1 - (num - 1) % factor;
}

Düzenle: Bu geri döner round_up(0,100)=100. Geri dönen bir çözüm için lütfen Paul'un aşağıdaki yorumuna bakın round_up(0,100)=0.


1
'Zaten çoklu' durumu işleyen en kısa vaka gibi görünüyor.
harningt

1
Pahalı işlem sayısı açısından en iyi çözüm. Sadece tek bir bölme kullanıyor ve çarpma yok
Niklas

3
round_up (0, 100) == Kabul edilen cevaptaki gibi 0 yerine 100
Gregory

7
Olmamalı mı num + factor - 1 - (num + factor - 1) % factor?
Paul

6
num - 1 - (num - 1) % factor + factortamsayı taşması riski olmadan aynı hesaplamayı yapar.

24

Bu, "bitlerin kaç bayt alacağını nasıl bulabilirim? (A: (n bit + 7) / 8) sorununun genelleştirilmesidir.

int RoundUp(int n, int roundTo)
{
    // fails on negative?  What does that mean?
    if (roundTo == 0) return 0;
    return ((n + roundTo - 1) / roundTo) * roundTo; // edit - fixed error
}

1
Bu, bir sayının bir sonraki katına yuvarlanmaz.
aaaa bbbb

7
Ben bu çözümü seviyorum çünkü eğer roundTo 2 gücü olacaksa, / ve * ortadan kaldırabilir ve ucuz işlemlerden başka bir şeyle sonuçlanamazsınız (x = roundTo - 1; return (n + x) & ~ x;)
Trejkaz

@Trejkaz hayır. (x = roundTo - 1; return (n+x)&~roundTo;)
Cevabımdaki

@KindDragon benim için yanlış sonuç üretir, ancak ~ roundTo yerine ~ x demek için düzeltirsem, beklenen sonucu elde ederim. Yine de Java 8'de.
Trejkaz

: @KindDragon VE ihtiyaçlarını maskelemek olmak 0xFFF...000değil, 0xFFF7FFF(ya 2'ye tümleyen olumsuzluk istiyorum böylece, ya da bir şey -: eksi) bir üzeri 2 veya bit-flip birinde az 2 (kişinin tamamlayıcı ters, bir gücünden daha ~: tildeli eksi değil). Yani (n+x) & ~xya da (n-roundTo+1) & -roundTo.
Peter Cordes

14
int roundUp(int numToRound, int multiple)
{
 if(multiple == 0)
 {
  return 0;
 }
 return ((numToRound - 1) / multiple + 1) * multiple;  
}

Ve koşullarla uğraşmaya gerek yok


10

Kısa ve tatlı bir cevap arayan herkes için. Ben bunu kullandım. Negatifler için muhasebe yok.

n - (n % r)

Bu önceki faktörü döndürecektir.

(n + r) - (n % r)

Bir sonraki dönecektir. Umarım bu birine yardımcı olur. :)


9
float roundUp(float number, float fixedBase) {
    if (fixedBase != 0 && number != 0) {
        float sign = number > 0 ? 1 : -1;
        number *= sign;
        number /= fixedBase;
        int fixedPoint = (int) ceil(number);
        number = fixedPoint * fixedBase;
        number *= sign;
    }
    return number;
}

Bu herhangi bir kayan sayı veya taban için geçerlidir (örneğin -4'ü en yakın 6.75'e yuvarlayabilirsiniz). Özünde, sabit bir noktaya dönüşüyor, oraya yuvarlanıyor, sonra geri dönüyor. Negatifleri 0'dan AWAY'i yuvarlayarak ele alır. Ayrıca işlevi esas olarak roundDown'a çevirerek değere negatif bir yuvarlama yapar.

Int'ye özgü bir sürüm şöyle görünür:

int roundUp(int number, int fixedBase) {
    if (fixedBase != 0 && number != 0) {
        int sign = number > 0 ? 1 : -1;
        int baseSign = fixedBase > 0 ? 1 : 0;
        number *= sign;
        int fixedPoint = (number + baseSign * (fixedBase - 1)) / fixedBase;
        number = fixedPoint * fixedBase;
        number *= sign;
    }
    return number;
}

Eklenen negatif giriş desteği ile az çok kaide cevabı.


Ben float roundUp kodunu çift ile test ettim, benim için çalışıyor. Sorunumu gerçekten çözer.
Ashif

1
Peki double round(double value, double multiple) { double sign = value; multiple = std::copysign(multiple, 1.0); value = std::copysign(value, 1.0); return std::copysign(multiple * std::ceil(value / multiple), sign); }ya yuvarlak almak için tavanı değiştirin.
Troyseph

8

Bu, float, çift, uzun, int ve kısa (ancak kullanılan çift değerler nedeniyle uzun uzun ve uzun çift için değil) için çalışan bir şablon işlevi kullanan modern c ++ yaklaşımıdır.

#include <cmath>
#include <iostream>

template<typename T>
T roundMultiple( T value, T multiple )
{
    if (multiple == 0) return value;
    return static_cast<T>(std::round(static_cast<double>(value)/static_cast<double>(multiple))*static_cast<double>(multiple));
}

int main()
{
    std::cout << roundMultiple(39298.0, 100.0) << std::endl;
    std::cout << roundMultiple(20930.0f, 1000.0f) << std::endl;
    std::cout << roundMultiple(287399, 10) << std::endl;
}

Ancak, aşağıda gösterildiği gibi kolayca şablon uzmanlığı long longve long doubleşablon uzmanlığı için destek ekleyebilirsiniz :

template<>
long double roundMultiple<long double>( long double value, long double multiple)
{
    if (multiple == 0.0l) return value;
    return std::round(value/multiple)*multiple;
}

template<>
long long roundMultiple<long long>( long long value, long long multiple)
{
    if (multiple == 0.0l) return value;
    return static_cast<long long>(std::round(static_cast<long double>(value)/static_cast<long double>(multiple))*static_cast<long double>(multiple));
}

Yuvarlamak üzere işlevler oluşturmak için std::ceilve her zaman kullanımı azaltmak için kullanın std::floor. Yukarıdaki örneğimi kullanarak yuvarlama std::round.

Aşağıda gösterildiği gibi "yuvarlak" veya daha iyi "yuvarlak tavan" şablon işlevini oluşturun:

template<typename T>
T roundCeilMultiple( T value, T multiple )
{
    if (multiple == 0) return value;
    return static_cast<T>(std::ceil(static_cast<double>(value)/static_cast<double>(multiple))*static_cast<double>(multiple));
}

Aşağıda gösterildiği gibi "yuvarlak aşağı" veya daha iyi "yuvarlak zemin" şablon işlevini oluşturun:

template<typename T>
T roundFloorMultiple( T value, T multiple )
{
    if (multiple == 0) return value;
    return static_cast<T>(std::floor(static_cast<double>(value)/static_cast<double>(multiple))*static_cast<double>(multiple));
}

1
artı 1, ancak bazı insanlar mulitple == 0
stijn

3
Dikkat edin, çünkü int64_t değerini ikiye dönüştürmek kayıplı olabilir, bu yüzden göründüğü kadar tip-jenerik değildir.
Adrian McCarthy

@AdrianMcCarthy Evet, yukarıda gösterildiği gibi doğru şablon uzmanlıkları oluşturmanız gerekir. Gördüğünüz gibi, long longve için iki ek fonksiyon uyguluyorum long double. Aynı şey diğer iki işlev için de açıkça yapılmalıdır.
Flovdis

Bence bu en yavaş olanıdır ama olmak zorunda değildir. Tek yapmanız gereken std :: enable_if_t ve tamsayılar ve kayan noktalar için iki dal yapmaktır. Ayrıca numeric_limits'i daha iyi kullanabilir ve mantisin gerçekten değere uyacak kadar büyük olup olmadığını görebilirsiniz. Bu güvenliği artıracaktır.
domuz

5

Öncelikle, hata durumunuzun (multiple == 0) muhtemelen bir dönüş değeri olmalıdır. Ne? Bilmiyorum. Belki bir istisna atmak istersiniz, bu size kalmış. Ancak, hiçbir şeyi iade etmek tehlikeli değildir.

İkinci olarak, numToRound'un zaten bir çoklu olmadığını kontrol etmelisiniz. Eklemek Aksi halde, multiplehiç roundDown, yanlış cevap alırsınız.

Üçüncü olarak, yayınlarınız yanlış. Sen dökme numToRoundbir tam sayıya, ama zaten bir tamsayı var. Bölme işleminden önce ikiye ve çarpma işleminden sonra int'e dönmeniz gerekir.

Son olarak, negatif sayılar için ne istiyorsunuz? "Yukarı" yuvarlama sıfıra yuvarlama (pozitif sayılarla aynı yönde yuvarlama) veya sıfırdan uzağa ("büyük" negatif sayı) yuvarlama anlamına gelebilir. Ya da, belki umursamazsın.

İşte ilk üç düzeltmeyi içeren bir sürüm, ancak olumsuz sorunla ilgilenmiyorum:

int roundUp(int numToRound, int multiple)
{
 if(multiple == 0)
 {
  return 0;
 }
 else if(numToRound % multiple == 0)
 {
  return numToRound
 }

 int roundDown = (int) (( (double) numToRound / multiple ) * multiple);
 int roundUp = roundDown + multiple; 
 int roundCalc = roundUp;
 return (roundCalc);
}

@Peter mi? Bunun int / intistediğimiz gibi bir int döndüreceğini varsaydım .
Mike Caron

int / int gerçekten bir int döndürür, ancak tam olarak istediğiniz budur. Örneğin, numToRound = 7, çoklu = 3. 7/3 = 2.
Peter Ruderman

4

İki Gücü Yuvarla:

Herhangi birinin iki gücün en yakın katına yuvarlanmış pozitif sayılar için bir çözüme ihtiyacı olması durumunda (çünkü bu şekilde burada kaldım):

// number: the number to be rounded (ex: 5, 123, 98345, etc.)
// pow2:   the power to be rounded to (ex: to round to 16, use '4')
int roundPow2 (int number, int pow2) {
    pow2--;                     // because (2 exp x) == (1 << (x -1))
    pow2 = 0x01 << pow2;

    pow2--;                     // because for any
                                //
                                // (x = 2 exp x)
                                //
                                // subtracting one will
                                // yield a field of ones
                                // which we can use in a
                                // bitwise OR

    number--;                   // yield a similar field for
                                // bitwise OR
    number = number | pow2;
    number++;                   // restore value by adding one back

    return number;
}

Giriş numarası zaten bir kat ise aynı kalacaktır.

GCC'nin verdiği x86_64 çıktısı -O2veya -Os(9Sep2013 Build - godbolt GCC online):

roundPow2(int, int):
    lea ecx, [rsi-1]
    mov eax, 1
    sub edi, 1
    sal eax, cl
    sub eax, 1
    or  eax, edi
    add eax, 1
    ret

Her C kod satırı montajdaki satırına mükemmel bir şekilde karşılık gelir: http://goo.gl/DZigfX

Bu talimatların her biri son derece hızlıdır , bu nedenle işlev de son derece hızlıdır. Kod çok küçük ve hızlı inlineolduğundan, kullanılırken işlev için yararlı olabilir .


Kredi:


1
Tam aradığım şey. Teşekkürler!
kiyo

1
int roundUpPow2 (int num, int pow2) {dönüş num + (pow2 - 1) & ~ (pow2 - 1); } yaklaşık% 30 daha hızlı ve kullanımı daha kolay (16'nın sonraki katına yuvarlamak için 16 değil 4'ü
geçiyorsunuz

3

Kullanıyorum:

template <class _Ty>
inline _Ty n_Align_Up(_Ty n_x, _Ty n_alignment)
{
    assert(n_alignment > 0);
    //n_x += (n_x >= 0)? n_alignment - 1 : 1 - n_alignment; // causes to round away from zero (greatest absolute value)
    n_x += (n_x >= 0)? n_alignment - 1 : -1; // causes to round up (towards positive infinity)
    //n_x += (_Ty(-(n_x >= 0)) & n_alignment) - 1; // the same as above, avoids branch and integer multiplication
    //n_x += n_alignment - 1; // only works for positive numbers (fastest)
    return n_x - n_x % n_alignment; // rounds negative towards zero
}

ve ikisinin gücü için:

template <class _Ty>
bool b_Is_POT(_Ty n_x)
{
    return !(n_x & (n_x - 1));
}

template <class _Ty>
inline _Ty n_Align_Up_POT(_Ty n_x, _Ty n_pot_alignment)
{
    assert(n_pot_alignment > 0);
    assert(b_Is_POT(n_pot_alignment)); // alignment must be power of two
    -- n_pot_alignment;
    return (n_x + n_pot_alignment) & ~n_pot_alignment; // rounds towards positive infinity (i.e. negative towards zero)
}

Bu negatif değerlerin her ikisinin de sıfıra (yani, tüm değerler için pozitif sonsuza yuvarlama anlamına gelir) yuvarlandığını, her ikisinin de imzalı taşmaya (C / C ++ 'da tanımlanmamış) dayanmadığını unutmayın.

Bu şunu verir:

n_Align_Up(10, 100) = 100
n_Align_Up(110, 100) = 200
n_Align_Up(0, 100) = 0
n_Align_Up(-10, 100) = 0
n_Align_Up(-110, 100) = -100
n_Align_Up(-210, 100) = -200
n_Align_Up_POT(10, 128) = 128
n_Align_Up_POT(130, 128) = 256
n_Align_Up_POT(0, 128) = 0
n_Align_Up_POT(-10, 128) = 0
n_Align_Up_POT(-130, 128) = -128
n_Align_Up_POT(-260, 128) = -256

n_Align_Up_POTDelphi'nin TList sınıfının içinde gördüğümden beri hiç kullanıyorum . Hizalama (çoklu) 2'nin gücü gibi kısıtlamaları vardır, ancak bu nadiren bir problemdir çünkü çoğunlukla SMID için doğru hizalamayı almak / kontrol etmek için kullanıyorum. Harika ve pek çok insan bunu bilmiyor gibi görünüyor.
user1593842

2

İç bölümün doğru sonucu üreteceğini bilmiyorsanız, yüzerlere dökmek ve tavan () kullanmak muhtemelen daha güvenlidir.


1
X86 tabanlı makinelerde yalnızca çiftin 54 bit anlamlı olabileceğini unutmayın. 64-bit girişiniz varsa, sonuçta başarısız olur.
domuz

IEEE754 standart çift olamaz ancak x64 cpus 80bit dahili kayan noktaya sahiptir, bu nedenle tek bir sayıdaki işlemler güvenilirdir
Martin Beckett

1
Bu doğru olsa da, C / C ++ 'dan yuvarlama üzerinde çok az kontrole sahipsiniz. Kontrol sözcüğü ayarlarına bağlıdır ve aslında 80 bit'ten daha azına yuvarlanabilir. Ayrıca, bu tür genişletilmiş aramadde olmayan SSE ve diğer SIMD talimat setleriniz var (vektörleştirici derleyici bunları kolayca kullanabilir).
domuz

2
int noOfMultiples = int((numToRound / multiple)+0.5);
return noOfMultiples*multiple

C ++ her sayıyı aşağı yuvarlar, bu nedenle 0,5 eklerseniz (1,5 ise 2 olur) ancak 1,49 1,99 olur 1.

EDIT - Üzgünüm yuvarlamak istediğiniz görmedim, +0.5 yerine bir ceil () yöntemi kullanmanızı öneririm


2

bir şey için, çünkü ne yapmak istediğini gerçekten anlamadım, çizgiler

int roundUp = roundDown + multiple;
int roundCalc = roundUp;
return (roundCalc); 

kesinlikle kısaltılabilir

int roundUp = roundDown + multiple;
return roundUp;

2

bu yardımcı olabilir:

int RoundUpToNearestMultOfNumber(int val, int num)
{
  assert(0 != num);
  return (floor((val + num) / num) * num);
}

Neden taban ve tamsayı bölme kullanılır? Katlanacak bir şey yok. Çift olsaydı, en azından negatif değerlerin işlenmesini devralabilirdiniz.
domuz

2

Daima yuvarlamak için

int alwaysRoundUp(int n, int multiple)
{
    if (n % multiple != 0) {
        n = ((n + multiple) / multiple) * multiple;

        // Another way
        //n = n - n % multiple + multiple;
    }

    return n;
}

alwaysRoundUp (1, 10) -> 10

alwaysRoundUp (5, 10) -> 10

alwaysRoundUp (10, 10) -> 10


Daima aşağı yuvarlamak

int alwaysRoundDown(int n, int multiple)
{
    n = (n / multiple) * multiple;

    return n;
}

alwaysRoundDown (1, 10) -> 0

alwaysRoundDown (5, 10) -> 0

alwaysRoundDown (10, 10) -> 10


Normal yolu yuvarlamak

int normalRound(int n, int multiple)
{
    n = ((n + multiple/2)/multiple) * multiple;

    return n;
}

normal Yuvarlak (1, 10) -> 0

Normal Yuvarlak (5, 10) -> 10

Normal Yuvarlak (10, 10) -> 10


2

2'nin gücü olan en yakın katına yuvarlayın

unsigned int round(unsigned int value, unsigned int multiple){
    return ((value-1u) & ~(multiple-1u)) + multiple;
}

Bu, istediğiniz yuvarlama artışının iki güç olduğu önbellekler boyunca tahsis etmek için yararlı olabilir, ancak elde edilen değerin yalnızca bunun bir katı olması gerekir. Açık gccBu fonksiyon gövdesinin bir bölümü ya da dalları ile 8 montaj talimatları oluşturur.

round(  0,  16) ->   0
round(  1,  16) ->  16
round( 16,  16) ->  16
round(257, 128) -> 384 (128 * 3)
round(333,   2) -> 334

1

Yukarıda yayınlanan birine benzer bir algoritma buldum:

int [(| x | + n-1) / n] * [(nx) / | x |]; burada x, kullanıcı giriş değeri ve n, kullanılan katmandır.

Tüm x değerleri için çalışır, burada x bir tamsayıdır (sıfır dahil pozitif veya negatif). Özellikle bir C ++ programı için yazdım, ancak bu temel olarak herhangi bir dilde uygulanabilir.


1

Negatif numToRound için:

Bunu yapmak gerçekten kolay olmalı, ancak standart modulo% operatörü beklendiği gibi negatif sayıları işlemez. Örneğin -14% 12 = -2 ve 10 değil. Yapılacak ilk şey, asla negatif sayı döndürmeyen modulo operatörünü elde etmektir. O zaman roundUp gerçekten basit.

public static int mod(int x, int n) 
{
    return ((x % n) + n) % n;
}

public static int roundUp(int numToRound, int multiple) 
{
    return numRound + mod(-numToRound, multiple);
}

1

Ben bunu yapardım:

#include <cmath>

int roundUp(int numToRound, int multiple)
{
    // if our number is zero, return immediately
   if (numToRound == 0)
        return multiple;

    // if multiplier is zero, return immediately
    if (multiple == 0)
        return numToRound;

    // how many times are number greater than multiple
    float rounds = static_cast<float>(numToRound) / static_cast<float>(multiple);

    // determine, whether if number is multiplier of multiple
    int floorRounds = static_cast<int>(floor(rounds));

    if (rounds - floorRounds > 0)
        // multiple is not multiplier of number -> advance to the next multiplier
        return (floorRounds+1) * multiple;
    else
        // multiple is multiplier of number -> return actual multiplier
        return (floorRounds) * multiple;
}

Kod optimum olmayabilir, ancak kuru performansa göre temiz kod tercih ederim.


Döküm intiçin floathali hazırda hassas kaybeder ve yanlış cevap için yapar.
chux - Monica

1
int roundUp (int numToRound, int multiple)
{
  return multiple * ((numToRound + multiple - 1) / multiple);
}

olmasına rağmen:

  • negatif sayılar için çalışmaz
  • numRound + birden fazla taşma durumunda çalışmaz

bunun yerine taşma davranışını tanımlayan imzasız tamsayıların kullanılmasını önerir.

Birden fazla == 0 bir istisna alırsınız, ancak yine de bu durumda iyi tanımlanmış bir sorun değildir.


1

c:

int roundUp(int numToRound, int multiple)
{
  return (multiple ? (((numToRound+multiple-1) / multiple) * multiple) : numToRound);
}

ve ~ / .bashrc için:

roundup()
{
  echo $(( ${2} ? ((${1}+${2}-1)/${2})*${2} : ${1} ))
}

1

Ben xzaten bir kat ise geri kalanı eklenmesini geçersiz kılmak için bir modül kombinasyonu kullanın :

int round_up(int x, int div)
{
    return x + (div - x % div) % div;
}

Kalanın tersini buluruz, sonra bölenle bölenin kendisi ise onu geçersiz kılmak için modül ekleriz x.

round_up(19, 3) = 21

1

İşte OP'nin önerisine ve herkes tarafından verilen örneklere dayanan çözümüm. Çoğu kişi negatif sayıları işlemek için aradığı için, bu çözüm, abs ve benzeri herhangi bir özel işlev kullanmadan bunu yapar.

Modülden kaçınarak ve bunun yerine bölünmeyi kullanarak, negatif sayı yuvarlatılmış olmasına rağmen doğal bir sonuçtur. Yuvarlatılmış sürüm hesaplandıktan sonra, negatif veya pozitif yönde yuvarlamak için gerekli matematiği yapar.

Ayrıca, hiçbir şeyi hesaplamak için özel işlevlerin kullanılmadığına dikkat edin, bu nedenle orada küçük bir hız artışı vardır.

int RoundUp(int n, int multiple)
{
    // prevent divide by 0 by returning n
    if (multiple == 0) return n;

    // calculate the rounded down version
    int roundedDown = n / multiple * multiple;

    // if the rounded version and original are the same, then return the original
    if (roundedDown == n) return n;

    // handle negative number and round up according to the sign
    // NOTE: if n is < 0 then subtract the multiple, otherwise add it
    return (n < 0) ? roundedDown - multiple : roundedDown + multiple;
}

İle başarısız RoundUp(INT_MIN, -1)olarak n / multipleise inttaşma.
chux - Monica

1

Bence bu sana yardımcı olacak. Aşağıdaki programı C dilinde yazdım.

# include <stdio.h>
int main()
{
  int i, j;
  printf("\nEnter Two Integers i and j...");
  scanf("%d %d", &i, &j);
  int Round_Off=i+j-i%j;
  printf("The Rounded Off Integer Is...%d\n", Round_Off);
  return 0;
}

0
/// Rounding up 'n' to the nearest multiple of number 'b'.
/// - Not tested for negative numbers.
/// \see http://stackoverflow.com/questions/3407012/
#define roundUp(n,b) ( (b)==0 ? (n) : ( ((n)+(b)-1) - (((n)-1)%(b)) ) )

/// \c test->roundUp().
void test_roundUp() {   
    // yes_roundUp(n,b) ( (b)==0 ? (n) : ( (n)%(b)==0 ? n : (n)+(b)-(n)%(b) ) )
    // yes_roundUp(n,b) ( (b)==0 ? (n) : ( ((n + b - 1) / b) * b ) )

    // no_roundUp(n,b) ( (n)%(b)==0 ? n : (b)*( (n)/(b) )+(b) )
    // no_roundUp(n,b) ( (n)+(b) - (n)%(b) )

if (true) // couldn't make it work without (?:)
{{  // test::roundUp()
    unsigned m;
                { m = roundUp(17,8); } ++m;
    assertTrue( 24 == roundUp(17,8) );
                { m = roundUp(24,8); }
    assertTrue( 24 == roundUp(24,8) );

    assertTrue( 24 == roundUp(24,4) );
    assertTrue( 24 == roundUp(23,4) );
                { m = roundUp(23,4); }
    assertTrue( 24 == roundUp(21,4) );

    assertTrue( 20 == roundUp(20,4) );
    assertTrue( 20 == roundUp(19,4) );
    assertTrue( 20 == roundUp(18,4) );
    assertTrue( 20 == roundUp(17,4) );

    assertTrue( 17 == roundUp(17,0) );
    assertTrue( 20 == roundUp(20,0) );
}}
}

0

Bu, pozitif tamsayılar için aradığınız sonuçları elde etmektir:

#include <iostream>
using namespace std;

int roundUp(int numToRound, int multiple);

int main() {
    cout << "answer is: " << roundUp(7, 100) << endl;
    cout << "answer is: " << roundUp(117, 100) << endl;
    cout << "answer is: " << roundUp(477, 100) << endl;
    cout << "answer is: " << roundUp(1077, 100) << endl;
    cout << "answer is: " << roundUp(52,20) << endl;
    cout << "answer is: " << roundUp(74,30) << endl;
    return 0;
}

int roundUp(int numToRound, int multiple) {
    if (multiple == 0) {
        return 0;
    }
    int result = (int) (numToRound / multiple) * multiple;
    if (numToRound % multiple) {
        result += multiple;
    } 
    return result;
}

Ve işte çıktılar:

answer is: 100
answer is: 200
answer is: 500
answer is: 1100
answer is: 60
answer is: 90

0

Bence bu işe yarıyor:

int roundUp(int numToRound, int multiple) {
    return multiple? !(numToRound%multiple)? numToRound : ((numToRound/multiple)+1)*multiple: numToRound;
}

-1

Bu benim için işe yarıyor ama olumsuzluklarla uğraşmaya çalışmadı

public static int roundUp(int numToRound, int multiple) {
    if (multiple == 0) {
        return 0;
    } else if (numToRound % multiple == 0) {
    return numToRound;
    }

    int mod = numToRound % multiple;
    int diff = multiple - mod;
    return numToRound + diff;
}

-3

İşte şıklık kavramını göstermek için süper basit bir çözüm. Temel olarak ızgaralar için.

(sözde kod)

nearestPos = Math.Ceil( numberToRound / multiple ) * multiple;

göndermeden önce fikrini kontrol ettin mi?
dozaj

Bu geçerli bir kod bile değil.
user13783520
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.