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
Robben_Ford_Fan_boy
sumber
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;
}
Mark tebusan
sumber
+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

KindDragon
sumber
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.

xlq
sumber
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
}
alas tiang
sumber
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

doron
sumber
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. :)

ikatan aaron
sumber
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.

Lumba-lumba
sumber
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));
}
Flovdis
sumber
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);
}
Mike Caron
sumber
@ 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:

haneefmubarak
sumber
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
babi
sumber
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.

Martin Beckett
sumber
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

Michal Ciechan
sumber
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;
Jesse Naugher
sumber
2

Mungkin ini dapat membantu:

int RoundUpToNearestMultOfNumber(int val, int num)
{
  assert(0 != num);
  return (floor((val + num) / num) * num);
}
Arsen
sumber
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

onmyway133
sumber
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
Anne Quinn
sumber
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.

Joshua Wade
sumber
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);
}
pengguna990343
sumber
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

Kena kau
sumber
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.

pengguna3392484
sumber
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} ))
}
nhed
sumber
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
Nick Bedford
sumber
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;
}
weatx
sumber
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;
}
Neel
sumber
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) );
}}
}
Adolfo
sumber
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
Dave
sumber
0

Saya pikir ini bekerja:

int roundUp(int numToRound, int multiple) {
    return multiple? !(numToRound%multiple)? numToRound : ((numToRound/multiple)+1)*multiple: numToRound;
}
pengguna13783520
sumber
-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;
}
pengguna1100538
sumber
-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;
Indivelope
sumber
apakah Anda memeriksa ide Anda sebelum mengirim? itu dosent memberikan jawaban
arus
Itu bahkan bukan kode yang valid.
user13783520