C ++: Membulatkan ke kelipatan angka terdekat


168

OK - saya hampir malu memposting ini di sini (dan saya akan menghapus jika ada orang yang memilih untuk menutup) karena sepertinya pertanyaan mendasar.

Apakah ini cara yang benar untuk mengumpulkan beberapa angka dalam C ++?

Saya tahu ada pertanyaan lain yang terkait dengan ini, tetapi saya secara khusus tertarik untuk mengetahui apa cara terbaik untuk melakukan ini di C ++:

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

Pembaruan: Maaf saya mungkin tidak menjelaskan maksudnya. Berikut ini beberapa contohnya:

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
Anda memiliki kesalahan dalam logika Anda - misalkan saya ingin membulatkan 4 hingga kelipatan 2. 2. roundDown = (4/2) * 2 = 4; roundUp = 4 + 2; jadi roundCalc = 6. Saya berasumsi bahwa Anda ingin mengembalikan 4 dalam kasus itu.
Niki Yoshiuchi

ini tidak berfungsi untuk roundUp (30,30). Itu memberi 60 sebagai jawaban, itu tetap memberi 30 sebagai jawaban ..
bsobaid

@bsobaid: Lihat jawaban saya di bagian bawah. Ini sedikit lebih sederhana daripada solusi lain di sini, meskipun itu harus bekerja juga
Niklas B.

3
Kasus uji Anda adalah contoh nyata yang hilang yang melibatkan angka negatif, kasus di mana pembagiannya tepat, kasus di mana pembagiannya hampir persis, dan kasus di mana angka-angka tersebut sangat dekat dengan batas kisaran int.

1
Robben_Ford_Fan_boy, Hasil edit dengan jawaban yang Anda pilih harus dihapus. Jika berbeda dari jawaban yang diberikan, Anda dapat memposting jawaban Anda sendiri. Seperti yang ada, jawaban itu memiliki masalah yang harus diatasi di bagian jawaban.
chux - Reinstate Monica

Jawaban:


161

Ini berfungsi untuk angka positif, tidak yakin tentang negatif. Ini hanya menggunakan bilangan bulat matematika.

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

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

    return numToRound + multiple - remainder;
}

Sunting: Ini adalah versi yang berfungsi dengan angka negatif, jika dengan "naik" yang Anda maksud adalah hasil yang selalu> = input.

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 Menurut pendapat saya, pasti solusi terbaik dan paling mudah dibaca.
Robben_Ford_Fan_boy

1
Tambahkan if(number<0){ multiple = multiple*(-1); }di awal untuk membulatkan angka negatif ke arah yang benar
Josh

4
@Josh: Mengapa menggunakan multiplikasi? if(number<0) multiple = -multiplelebih mudah.
md5

ini tidak berfungsi untuk roundUp (30,30). Itu memberi 60 sebagai jawaban, masih harus memberi 30 sebagai jawaban.
bsobaid

@bobaid tidak mungkin. The if (remainder == 0)uji harus mengurus kasus itu. Ini berfungsi untuk saya: ideone.com/Waol7B
Mark Ransom

114

Tanpa syarat:

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

Ini berfungsi seperti pembulatan dari nol untuk angka negatif

EDIT: Versi yang berfungsi juga untuk angka negatif

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

Tes


If multipleadalah kekuatan 2 (lebih cepat ~ 3,7 kali http://quick-bench.com/sgPEZV9AUDqtx2uujRSa3-eTE80 )

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

Tes


24
+1 untuk kekuatan 2 versi. Sangat berguna karena benar-benar menghindari biaya perkalian, pembagian atau modulo.
Nikos C.

Apakah Anda yakin bahwa algoritma ini tidak memiliki prasyarat? Bagaimana dengan angka negatif? Perilaku ini tampaknya tidak terdefinisi pada pra-C ++ 11 .
cubuspl42

> Bagaimana dengan angka negatif? Seperti dijelaskan, ini berfungsi untuk angka negatif seperti pembulatan dari nol.
KindDragon

Saya membaca "pembulatan" sebagai makna pembulatan menuju infinity positif, bukan pembulatan dari nol.

8
Perhatikan bahwa & ~(x - 1)sama dengan & -xaritmatika komplemen dua.
Todd Lehman

39

Ini berfungsi ketika faktor akan selalu positif:

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

Sunting: Ini kembali round_up(0,100)=100. Silakan lihat komentar Paul di bawah ini untuk solusi yang kembali round_up(0,100)=0.


1
Tampaknya menjadi kasus terpendek yang menangani kasus 'sudah-menjadi-banyak'.
harningt

1
Solusi terbaik dalam hal jumlah operasi yang mahal. Hanya menggunakan satu divisi dan tidak ada multiplikasi
Niklas B.

3
round_up (0, 100) == 100 bukannya 0 seperti pada jawaban yang diterima
Gregory

7
Bukankah seharusnya begitu num + factor - 1 - (num + factor - 1) % factor?
Paul

6
num - 1 - (num - 1) % factor + factormelakukan perhitungan yang sama tanpa risiko integer overflow.

24

Ini adalah generalisasi dari masalah "bagaimana cara mencari tahu berapa banyak byte n bit yang akan diambil? (A: (n bits + 7) / 8).

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
Ini tidak cocok dengan kelipatan angka berikutnya.
aaaa bbbb

7
Saya suka solusi ini karena jika roundTo akan menjadi kekuatan 2, Anda dapat menghilangkan / dan * dan berakhir dengan operasi murah (x = roundTo - 1; return (n + x) & ~ x;)
Trejkaz

@Trejkaz nggak. Seharusnya (x = roundTo - 1; return (n+x)&~roundTo;)seperti dalam jawaban saya
KindDragon

@IndDragon yang menghasilkan hasil yang salah untuk saya, tetapi jika saya memperbaikinya dengan mengatakan ~ x bukannya ~ roundTo, saya mendapatkan hasil yang diharapkan. Di Java 8 pula.
Trejkaz

@IndDragon: Topeng AND harus 0xFFF...000, bukan 0xFFF7FFFatau sesuatu, jadi Anda ingin negasi komplemen 2's ( -: minus) pada kekuatan 2, atau bit-flip pada yang kurang dari kekuatan 2 (invers komplemen satu ~,: tilde bukan minus). Jadi (n+x) & ~xatau (n-roundTo+1) & -roundTo.
Peter Cordes

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

Dan tidak perlu dipusingkan dengan kondisi


11

Bagi siapa pun yang mencari jawaban pendek dan manis. Inilah yang saya gunakan. Tidak ada akuntansi untuk negatif.

n - (n % r)

Itu akan mengembalikan faktor sebelumnya.

(n + r) - (n % r)

Akan kembali berikutnya. Semoga ini bisa membantu seseorang. :)


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

Ini berfungsi untuk semua nomor atau basis float (mis. Anda dapat membulatkan -4 ke 6.75 terdekat). Intinya itu mengkonversi ke titik tetap, membulatkan ke sana, lalu mengubahnya kembali. Ini menangani negatif dengan membulatkan AWAY dari 0. Ini juga menangani putaran negatif ke nilai dengan dasarnya mengubah fungsi menjadi roundDown.

Versi int khusus terlihat seperti:

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

Yang kurang lebih jawaban alas, dengan dukungan input negatif yang ditambahkan.


Saya telah menguji kode float roundUp dengan ganda, ini berfungsi untuk saya. Benar-benar menyelesaikan masalah saya.
Ashif

1
Bagaimana 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); }Atau bertukar ceil untuk mendapatkan pembulatan.
Troyseph

8

Ini adalah pendekatan c ++ modern menggunakan fungsi templat yang berfungsi untuk float, double, long, int dan short (tetapi tidak untuk long, dan long double karena nilai ganda yang digunakan).

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

Tetapi Anda dapat dengan mudah menambahkan dukungan untuk long longdan long doubledengan spesialisasi templat seperti yang ditunjukkan di bawah ini:

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

Untuk membuat fungsi untuk mengumpulkan, gunakan std::ceildan untuk selalu digunakan std::floor. Contoh saya dari atas adalah pembulatan menggunakan std::round.

Buat fungsi templat "bulat" atau lebih dikenal sebagai "plafon bundar" seperti yang ditunjukkan di bawah ini:

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

Buat fungsi template "bulat ke bawah" atau lebih dikenal sebagai "putaran lantai" seperti yang ditunjukkan di bawah ini:

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
ditambah 1, meskipun beberapa orang mungkin merasa lebih beresonansi untuk mengembalikan 0 ketika mulitple == 0
stijn

3
Berhati-hatilah, karena mengubah int64_t menjadi dua kali lipat bisa menjadi lossy, jadi itu tidak cukup sebagai tipe generik seperti yang mungkin muncul.
Adrian McCarthy

@AdrianMcCarthy Ya Anda harus membuat spesialisasi templat yang benar seperti yang ditunjukkan di atas. Seperti yang Anda lihat, saya menerapkan dua fungsi tambahan untuk long longdan long double. Hal yang sama harus dilakukan untuk dua fungsi lainnya.
Flovdis

Saya pikir ini adalah yang paling lambat dari semua tetapi tidak harus. Yang perlu Anda lakukan adalah std :: enable_if_t dan melakukan dua cabang untuk integer dan float. Anda juga dapat menggunakan numeric_limits dengan lebih baik dan melihat apakah mantissa cukup besar untuk benar-benar sesuai dengan nilainya. Itu akan menambah keamanan.
babi

5

Pertama, kondisi kesalahan Anda (beberapa == 0) mungkin harus memiliki nilai balik. Apa? Saya tidak tahu Mungkin Anda ingin melempar pengecualian, itu terserah Anda. Tapi, mengembalikan tidak ada yang berbahaya.

Kedua, Anda harus memeriksa bahwa numToRound belum banyak. Jika tidak, ketika Anda menambahkan multipleuntuk roundDown, Anda akan mendapatkan jawaban yang salah.

Ketiga, gips Anda salah. Anda numToRoundmemasukkan bilangan bulat, tetapi itu sudah bilangan bulat. Anda perlu melakukan casting untuk menggandakan sebelum divisi, dan kembali ke int setelah multiplikasi.

Terakhir, apa yang Anda inginkan untuk angka negatif? Membulatkan "ke atas" dapat berarti membulatkan ke nol (membulatkan ke arah yang sama dengan angka positif), atau menjauh dari nol (angka negatif "lebih besar"). Atau, mungkin Anda tidak peduli.

Ini adalah versi dengan tiga perbaikan pertama, tapi saya tidak berurusan dengan masalah negatif:

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 Apakah itu? Saya berasumsi bahwa int / intakan mengembalikan int, yang bukan itu yang kita inginkan.
Mike Caron

int / int memang mengembalikan int, tapi itulah yang Anda inginkan. Sebagai contoh, numToRound = 7, multiple = 3. 7/3 = 2.
Peter Ruderman

4

Round to Power of Two:

Untuk berjaga-jaga kalau-kalau ada yang membutuhkan solusi untuk bilangan positif dibulatkan ke kelipatan dua kekuatan terdekat (karena itulah saya berakhir di sini):

// 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;
}

Nomor input akan tetap sama jika sudah banyak.

Berikut ini adalah keluaran x86_64 yang diberikan GCC -O2atau -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

Setiap baris kode C sangat cocok dengan barisnya dalam rakitan: http://goo.gl/DZigfX

Masing-masing instruksi tersebut sangat cepat , sehingga fungsinya juga sangat cepat. Karena kodenya sangat kecil dan cepat, mungkin berguna untuk inlinefungsinya saat menggunakannya.


Kredit:


1
Persis apa yang saya cari. Terima kasih!
kiyo

1
int roundUpPow2 (int num, int pow2) {return num + (pow2 - 1) & ~ (pow2 - 1); } adalah sekitar 30% lebih cepat, dan lebih mudah digunakan (Anda melewati 16 bukan 4 untuk membulatkan ke kelipatan 16 berikutnya.
Axel Rietschin

3

Saya menggunakan:

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
}

dan untuk kekuatan dua:

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

Perhatikan bahwa kedua putaran tersebut bernilai negatif menuju nol (itu berarti bulat hingga tak terhingga positif untuk semua nilai), tidak satu pun dari keduanya bergantung pada limpahan yang ditandatangani (yang tidak ditentukan dalam C / C ++).

Ini memberi:

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

Saya telah menggunakan Anda n_Align_Up_POTsejak saya melihatnya di dalam kelas TList Delphi. Ini memiliki batasannya, seperti perataan (banyak) menjadi kekuatan 2, tapi itu jarang menjadi masalah karena saya kebanyakan menggunakannya untuk mendapatkan / memeriksa perataan yang benar untuk SMID. Itu luar biasa dan sepertinya tidak banyak orang tahu tentang itu.
user1593842

2

Mungkin lebih aman untuk dilemparkan ke float dan menggunakan ceil () - kecuali Anda tahu bahwa divisi int akan menghasilkan hasil yang benar.


1
Perhatikan bahwa double hanya dapat menampung 54 bit signifikansi pada mesin berbasis x86. Jika Anda memiliki int 64-bit, akhirnya akan gagal.
babi

Standar ganda IEEE754 tidak bisa lain kecuali x64 cpus memiliki floating point internal 80bit sehingga operasi pada nomor tunggal dapat diandalkan
Martin Beckett

1
Meskipun itu benar, Anda memiliki sedikit kontrol atas pembulatan dari C / C ++. Itu tergantung pada pengaturan kata kontrol dan itu mungkin benar-benar dibulatkan menjadi kurang dari 80 bit. Anda juga memiliki SSE dan set instruksi SIMD lainnya yang tidak memiliki perantara lanjutan (kompiler pengubah vektor dapat dengan mudah menggunakannya).
babi

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

C ++ membulatkan setiap angka ke bawah, jadi jika Anda menambahkan 0,5 (jika 1,5 maka akan menjadi 2) tetapi 1,49 akan menjadi 1,99 karena itu 1.

EDIT - Maaf tidak melihat Anda ingin mengumpulkan, saya sarankan menggunakan metode ceil () alih-alih +0.5


2

baik untuk satu hal, karena saya tidak benar-benar mengerti apa yang ingin Anda lakukan, garis

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

pasti bisa disingkat

int roundUp = roundDown + multiple;
return roundUp;

2

Mungkin ini dapat membantu:

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

Mengapa menggunakan divisi floor dan integer? Tidak ada apa-apa ke lantai. Jika dobel, Anda setidaknya bisa mewarisi penanganan nilai negatif.
babi

2

Untuk selalu mengumpulkan

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


Selalu bulat

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

    return n;
}

alwaysRoundDown (1, 10) -> 0

alwaysRoundDown (5, 10) -> 0

alwaysRoundDown (10, 10) -> 10


Untuk membulatkannya dengan cara biasa

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

    return n;
}

normalRound (1, 10) -> 0

normalRound (5, 10) -> 10

normalRound (10, 10) -> 10


2

Membulatkan ke kelipatan terdekat yang terjadi menjadi kekuatan 2

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

Ini bisa berguna ketika mengalokasikan bersama bujangan, di mana kenaikan pembulatan yang Anda inginkan adalah kekuatan dua, tetapi nilai yang dihasilkan hanya perlu kelipatannya. Pada gcctubuh fungsi ini menghasilkan 8 instruksi perakitan tanpa divisi atau cabang.

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

1

Saya menemukan algoritma yang agak mirip dengan yang diposting di atas:

int [(| x | + n-1) / n] * [(nx) / | x |], di mana x adalah nilai input pengguna dan n adalah multiple yang digunakan.

Ia bekerja untuk semua nilai x, di mana x adalah bilangan bulat (positif atau negatif, termasuk nol). Saya menulisnya secara khusus untuk program C ++, tetapi ini pada dasarnya dapat diimplementasikan dalam bahasa apa pun.


1

Untuk numToRound negatif:

Seharusnya sangat mudah untuk melakukan ini tetapi modulo% operator standar tidak menangani angka negatif seperti yang mungkin diharapkan. Misalnya -14% 12 = -2 dan bukan 10. Hal pertama yang harus dilakukan adalah mendapatkan operator modulo yang tidak pernah mengembalikan angka negatif. Maka roundUp sangat sederhana.

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

Inilah yang akan saya lakukan:

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

Kode mungkin tidak optimal, tapi saya lebih suka kode bersih daripada kinerja kering


Casting intuntuk floatsiap kehilangan presisi dan membuat jawaban yang salah.
chux - Reinstate Monica

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

meskipun:

  • tidak akan berfungsi untuk angka negatif
  • tidak akan berfungsi jika numRound + multiple overflow

akan menyarankan menggunakan bilangan bulat yang tidak ditandatangani sebagai gantinya, yang telah mendefinisikan perilaku overflow.

Anda akan mendapatkan pengecualian beberapa == 0, tapi itu bukan masalah yang didefinisikan dengan baik dalam kasus itu.


1

c:

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

dan untuk ~ / .bashrc Anda:

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

1

Saya menggunakan kombinasi modulus untuk membatalkan penambahan sisanya jika xsudah beberapa:

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

Kami menemukan kebalikan dari sisanya kemudian modulus dengan pembagi lagi untuk membatalkannya jika pembagi itu sendiri kemudian tambahkan x.

round_up(19, 3) = 21

1

Inilah solusi saya berdasarkan saran OP, dan contoh-contoh yang diberikan oleh orang lain. Karena sebagian besar semua orang mencarinya untuk menangani angka negatif, solusi ini tidak hanya itu, tanpa menggunakan fungsi khusus, yaitu abs, dan sejenisnya.

Dengan menghindari modulus dan sebagai gantinya menggunakan pembagian, angka negatif adalah hasil alami, meskipun dibulatkan ke bawah. Setelah versi dibulatkan dihitung, maka diperlukan matematika untuk mengumpulkan, baik dalam arah negatif atau positif.

Perhatikan juga bahwa tidak ada fungsi khusus yang digunakan untuk menghitung apa pun, sehingga ada peningkatan kecepatan kecil di sana.

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

Gagal dengan RoundUp(INT_MIN, -1)apa n / multipleyang intmeluap.
chux

1

Saya pikir ini akan membantu Anda. Saya telah menulis program di bawah ini dalam C.

# 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

Ini mendapatkan hasil yang Anda cari untuk bilangan bulat positif:

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

Dan inilah outputnya:

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

0

Saya pikir ini bekerja:

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

-1

Ini bekerja untuk saya tetapi tidak mencoba untuk menangani yang negatif

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

-2

Berikut ini adalah solusi super sederhana untuk menunjukkan konsep keanggunan. Ini pada dasarnya untuk terkunci jaringan.

(kode semu)

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

apakah Anda memeriksa ide Anda sebelum mengirim? itu dosent memberikan jawaban
arus

Itu bahkan bukan kode yang valid.
user13783520
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.