Home » Создание сайтов и программирование » Почему Round "раундит" "не правильно" или все про округление в .NET

Почему Round "раундит" "не правильно" или все про округление в .NET

Как Вы думаете, какой результат получится в результате выполнения этого кода:

Если Вы думаете, что получится 4 и 5, то ошибаетесь. В обоих случаях результатом будет 4. Тот же самый результат Вы получите и в Visual Basic 6.0. В .NET статический метод Round() класса Math округляет половину к ближайшему четному. В школе же нас учили, что половина всегда округляется в большую сторону. Поэтому многие (и я в том числе) очень удивляются, узнав о таком “неправильном” округлении. Часто незнание этого факта может привести к неправильным расчетам, если алгоритмы преполагают “обычное” округление.

Что же это такое? Очередной баг Microsoft? Вовсе нет! Просто существует несколько способов округления.

Округление в меньшую сторону

Простейший случай – когда цифры после заданной точности просто отбрасываются (округляем до целого):

3.9 округляется до 3
-3.9 округляется до -3

Это, так называемое, симметричное округление, когда число округляется только по абсолютной величине, без учета знака.
В .NET симметричное округление в меньшую сторону производится простым привидением к целому:

С учетом знака -3.9 округляется до -4. Метод Floor() класса Math производит несимметричное округление:

Округление в большую сторону

Несимметричное округление до ближайшего большего или равного целого выполняет метод Ceiling() класса Math:

Заметьте, что Floor() и Ceiling() округляют всегда до целого.

Но чаще всего приходится округлять не в меньшую или большую сторону, а к ближайшему числу (с заданной точностью). В этом случае погрешность будет меньшей. Главный вопрос, который возникает в этом случае – как округлять половину?

Арифметическое округление

Это привычное нам округление, когда половина округляется в большую сторону:

3.5 округляется до 4
4.5 округляется до 5

Как и в предыдущих случаях, можно рассматривать симметричное и несимметричное арифметическое округление.

Банковское округление

Если складывать много чисел, округляя .5 всегда в большую сторону, то возникнет перекос, который будет тем больше, чем больше чисел мы складываем. Банковское округление позволяет минимизировать этот перекос. В этом случае половина округляется к ближайшему четному. Метод Round() класса Math реализует именно банковское округление. В качестве параметра он принимает округляемое значение и, возможно, точность, до которой необходимо выполнить округление. Если точность не указана, то округление выполняется до целого.

Случайное округление

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

Попеременное (alternate) округление

В этом случае .5 округляется попеременно то в большую сторону, то в меньшую.

Что же делать, если надо произвести арифметическое округление? К сожалению, Microsoft не реализовала соответствующий метод в классе Math (так же, как и для случайного и попеременного округлений). Но выход, конечно, есть.

Во первых, это класс SqlDecimal из пространства имен System.Data.SqlTypes со статическим методом Round:

Это отличие связано с тем, что Round из Sql Server выполняет математическое округление.

Во вторых, можно самостоятельно написать метод для математического (и не только) округления. Например, вот реализация на C# для симметричного арифметического округления.

Я предпочитаю поместить несколько перегрузок приведенной реализации (для float, double, decimal) в некоторый служебный класс и использовать их вместо Math.Round() (мне пока не приходилось реализовывать задачи, требующие банковского округления).

Реализацию описанных алгоритмов округления на Visual Basic 6.0 можно найти здесь: http://support.microsoft.com/default.aspx?scid=kb;en-us;196652

Добавлено 25.10.2005

В .NET 2.0 метод Round() класса Math имеет перегрузки с параметром mode типа MidpointRounding, определяющим, как будет округляться половина. MidpointRounding может принимать два значения:

  • AwayFromZero – половина округляется к ближайшему числу, которое дальше от нуля (т.е обыкновенное математическое симметричное округление).
  • ToEven – округление половины к ближайшему четному – единственная текущая реализация Round(). Естественно, если параметр mode не задан, по умолчанию используется ToEven (для совместимости).

buy abilify buy accutane buy aceon buy aciphex buy actos buy adalat buy aggrenox buy albenza buy aldactone buy alesse buy allegra buy alprostadil buy altace buy amalaki buy amaryl buy amoxil buy anafranil buy antabuse buy arava buy arcoxia buy aricept buy arjuna buy artane buy asacol buy astelin buy atarax buy augmentin buy avalide buy avapro buy avelox buy avodart buy ayurslim buy azulfidine buy bactrim buy bactroban buy benicar buy betagan buy betnovate buy biaxin buy bimatoprost buy botox buy brahmi buy buspar buy bystolic buy calan buy cardura buy casodex buy cefixime buy ceftin buy celebrex buy celexa buy cenforce buy chloromycetin buy cialis buy cipro buy clarinex buy claritin buy cleocin buy clomid buy combivir buy copegus buy cordarone buy coreg buy coumadin buy cozaar buy crestor buy cymbalta buy cytoxan buy deltasone buy depakote buy desyrel buy detrol buy diabecon buy diamox buy diflucan buy diovan buy duphaston buy duricef buy effexor buy elavil buy eldepryl buy epivir buy eulexin buy evecare buy evista buy exelon buy famvir buy feldene buy flagyl buy fliban buy flomax buy flonase buy floxin buy geodon buy glucophage buy glucotrol buy glucovance buy grifulvin buy guduchi buy haridra buy himplasia buy hytrin buy hyzaar buy ilosone buy imdur buy imitrex buy imodium buy inderal buy indocin buy janya buy kapikachhu buy karela buy keflex buy kemadrin buy lamictal buy lanoxin buy lasix buy lasuna buy levaquin buy levitra buy lexapro buy lioresal buy lipitor buy lopid buy lopressor buy lozol buy luvox buy manjishtha buy megaslim buy menosan buy meshashringi buy mestinon buy metaglip buy micardis buy micronase buy microzide buy minipress buy mobic buy moduretic buy motilium buy motrin buy myambutol buy mysoline buy naprosyn buy neem buy neurontin buy nexium buy nizoral buy nolvadex buy noroxin buy norvasc buy omnicef buy oxytrol buy pamelor buy paracetamol buy parlodel buy paxil buy penisole buy periactin buy persantine buy plavix buy ponstel buy prandin buy precose buy prednisone buy prevacid buy priligy buy prilosec buy prograf buy propecia buy proscar buy protonix buy provestra buy punarnava buy rebetol buy reglan buy requip buy retrovir buy risperdal buy rulide buy serevent buy seroquel buy shallaki buy shatavari buy shigru buy sinemet buy sinequan buy singulair buy speman buy sporanox buy starlix buy strattera buy stromectol buy sumycin buy suprax buy sustiva buy symmetrel buy tegretol buy tenoretic buy terramycin buy tofranil buy topamax buy trandate buy trental buy tricor buy trikatu buy trileptal buy triphala buy tulasi buy urispas buy uroxatral buy valtrex buy vantin buy vasaka buy vasotec buy ventolin buy vermox buy viagra buy vigorelle buy vigrx buy voltaren buy vrikshamla buy vytorin buy wondersleep buy xenical buy zanaflex buy zantac buy zebeta buy zestoretic buy zetia buy ziac buy zithromax buy zocor buy zofran buy zoloft buy zovirax buy zyloprim buy zyrtec viagra

buy abilify buy accutane buy aceon buy aciphex buy actos buy adalat buy aggrenox buy albenza buy aldactone buy alesse buy allegra buy alprostadil buy altace buy amalaki buy amaryl buy amoxil buy anafranil buy antabuse buy arava buy arcoxia buy aricept buy arjuna buy artane buy asacol buy astelin buy atarax buy augmentin buy avalide buy avapro buy avelox buy avodart buy ayurslim buy azulfidine buy bactrim buy bactroban buy benicar buy betagan buy betnovate buy biaxin buy bimatoprost buy botox buy brahmi buy buspar buy bystolic buy calan buy cardura buy casodex buy cefixime buy ceftin buy celebrex buy celexa buy cenforce buy chloromycetin buy cialis buy cipro buy clarinex buy claritin buy cleocin buy clomid buy combivir buy copegus buy cordarone buy coreg buy coumadin buy cozaar buy crestor buy cymbalta buy cytoxan buy deltasone buy depakote buy desyrel buy detrol buy diabecon buy diamox buy diflucan buy diovan buy duphaston buy duricef buy effexor buy elavil buy eldepryl buy epivir buy eulexin buy evecare buy evista buy exelon buy famvir buy feldene buy flagyl buy fliban buy flomax buy flonase buy floxin buy geodon buy glucophage buy glucotrol buy glucovance buy grifulvin buy guduchi buy haridra buy himplasia buy hytrin buy hyzaar buy ilosone buy imdur buy imitrex buy imodium buy inderal buy indocin buy janya buy kapikachhu buy karela buy keflex buy kemadrin buy lamictal buy lanoxin buy lasix buy lasuna buy levaquin buy levitra buy lexapro buy lioresal buy lipitor buy lopid buy lopressor buy lozol buy luvox buy manjishtha buy megaslim buy menosan buy meshashringi buy mestinon buy metaglip buy micardis buy micronase buy microzide buy minipress buy mobic buy moduretic buy motilium buy motrin buy myambutol buy mysoline buy naprosyn buy neem buy neurontin buy nexium buy nizoral buy nolvadex buy noroxin buy norvasc buy omnicef buy oxytrol buy pamelor buy paracetamol buy parlodel buy paxil buy penisole buy periactin buy persantine buy plavix buy ponstel buy prandin buy precose buy prednisone buy prevacid buy priligy buy prilosec buy prograf buy propecia buy proscar buy protonix buy provestra buy punarnava buy rebetol buy reglan buy requip buy retrovir buy risperdal buy rulide buy serevent buy seroquel buy shallaki buy shatavari buy shigru buy sinemet buy sinequan buy singulair buy speman buy sporanox buy starlix buy strattera buy stromectol buy sumycin buy suprax buy sustiva buy symmetrel buy tegretol buy tenoretic buy terramycin buy tofranil buy topamax buy trandate buy trental buy tricor buy trikatu buy trileptal buy triphala buy tulasi buy urispas buy uroxatral buy valtrex buy vantin buy vasaka buy vasotec buy ventolin buy vermox buy viagra buy vigorelle buy vigrx buy voltaren buy vrikshamla buy vytorin buy wondersleep buy xenical buy zanaflex buy zantac buy zebeta buy zestoretic buy zetia buy ziac buy zithromax buy zocor buy zofran buy zoloft buy zovirax buy zyloprim buy zyrtec viagra

cialis effects cialis sample stendra vs viagra non prescribed viagra when will cialis go generic viagra coupons from pfizer discount cialis otc viagra what is amoxicillin used for viagra coupons viagra coupons 75 off viagra pill cialis vs viagra discount viagra amoxicillin 500 mg and alcohol viagra canada viagra single packs viagra costs cialis 10 mg axoloti cheap viagra viagra price amoxicillin clavulanate viamedic cialis how much does cialis cost amoxicillin dosage dosage of amoxicillin side effect of amoxicillin viagra activate cialis daily cialis amoxil dosage cost of cialis cialis 5mg daily amoxillin where to buy viagra viagra dosage generic viagra 100mg is viagra government funded in america buy cialis amoxicillin side effects in men levitra vs viagra viagra online healthy man viagra viagra patent expiration women viagra viagra on line no prec is viagra government funded amoxicillin 500mg capsules what does viagra do cialis patent expiration date extended natural viagra amoxin generic viagra available in usa side effects of amoxicillin viagra from amazon cialis coupons printable amoxycillin augmentin drug class canada cialis amoxicillin 500 cyalis amoxicillin side effects in women cialis for bph natural viagra alternatives that work cialis for sale cialis cheap amoxicillin tablets utilisation viagra cialis generic cialis coupon 20 mg inexpensive viagra pills cialis online viagra pills for sale viagra porn generic viagra viagra from canada cialis otc cialis 20mg directions daily cialis generic for viagra axolotls over the counter viagra cialis copay card cialis on line cialis testimonials amoxicillin rash how long does viagra last side effects of amoxicillin 500 mg cialis canada cialis price does the government fund viagra axoltl viagra vs cialis vs levitra viagra samples generic for cialis cialis website side effects of viagra viagra cialis side effects of cialis augmentin 500 amoxicillin 875 mg viagra generic cialis 30 day sample amoxicillin buy viagra how much does viagra cost cialis samples overnight amoxicillin dosing cialis coupon print female viagra amoxil 500 mg viagra lowest cialis prices is viagra covered by insurance cialis generic availability cialis dosage cialis patent expiration generic cialis what is anoxia amoxicillin side effects viagra pharmacy cialis side effects online viagra online cialis amoxcillin cialis prices best price viagra trimox liquid cialis herbal viagra cialis 5mg viagra government funded axolotl amox-clav 875-125 mg cialis canadian pharmacy revatio vs viagra amox-clav 875-125 amoxicillin 500 mg for sinus infection cialis pricing buy cialis online canadian viagra viagra cost sildenafil vs viagra moxil amox-clav 875-125 mg tablet viagra savings offer amoxicilina amoxi amox clav 875-125 viagra without prescription amovil axlotl viagra prices pfizer viagra coupons amox clav 875 canada viagra viagra without a doctor prescription cialis from canada is viagra funded by government cialis trial viagra ingredients sex viagra for women erectile dysfunction cialis free viagra amoxicillin uses amoxicillin for cats cheap cialis viagra government funding cialis vs viagra cialis savings card mexican salamander cialis for women cialis voucher amoxicillin medscape amoxicillin uti does viagra work order online viagra cialis professional cialis dosage recommendations cialis pills for sale amoxicillan cilias viagra for sale price cialis walgreens viagra substitute viagra vs cialis cialis 20 mg viagra sex cialis alternative what is amoxicillin cialis coupon cialis reviews cialis dosage strengths how does viagra work cialis samples viagra substitute viagra 100mg tablets retail price viagra vs cialis cialis free trial viagra without a doctor prescription usa pfizer viagra female viagra pills generic cialis at walmart viagra side effects amoxicillin and clavulanate potassium 875 125 cialis 30 day trial coupon generic cialis tadalafil amoxidal amoxicillin 500mg cialis pills viagra 100mg price walmart anadrol amoxicillian augmentin 875-125 cialis cost amoxicillin 500 mg amoxicillin/clavulanic acid amoxacilin cialis coupons from manufacturer axolotyl xolotl viagra pills viagra on line viagra for women cialis pharmacy prices amox/k clav 875-125 cialis medication cialis tadalafil cialis coupons 2017 tamoxifen viagra girls cialas trial viagra sample how to take cialis cialis for daily use sophia viagra cialis for men cialis patent expiration 2017 viagra coupon cialis or viagra cialis without a doctor’s prescription mexican walking fish free cialis wholesale cialis viagra dose cialis generic tadalafil cialis coupons is viagra federally funded cealis augmentin dosage amox canadian cialis viagra best price cialis 5 mg what is cialis amoxicillin 250mg cvs pharmacy viagra coupons viagra alternatives cialis discount viagra prices without insurance buy viagra online what is viagra cost of viagra how does cialis work viagra single packs cost axolot cialis or viagra amoxicilin amoxil cialis 20mg 200 cialis coupon amoxicillin trihydrate 500mg

  • Rometsss

    Пора мелкософту гнать своих индусов с их “восхитительной” логикой и миропредставлением :)
    А потом у них винда и прочие приложения глючат почемуто…
    Обычная арифметика: 30-20=10, как у десяти может быть середина? там с одной стороны 0-4 (5 цифр) и с другой 5-9 (5 цифр)!

    • А при чем здесь индусы? Просто есть разные способы округления, о которых я рассказал в статье, и в первой версии .NET использовался не тот, к котрому привыкли мы. В этом нет ничего страшного, если знать.

      Ноль после запятой не учитывается, так что цифр, которые надо округлять, остается 9. И цифра 5 – середина.

  • Dasistgut

    А если ещё немножко подумать, то округлять надо результат, а не слагаемые.

    • А если еще подумать, то можно понять, что слагаемые, например, могут уже храниться в базе. В любом случае, результат можно округлять по разному (о чем и идет речь в статье).

  • Venom

    > простым привидением 

  • tarenych

    есть еще волшебные округления чисел в/за пределами 32768
    пример
    32767.075 32767.08
    32768.075 32768.07

    так округляет и Math.Round(32768.075, 2, MidpointRounding.AwayFromZero) и public static double Round(32768.075, 2)

    • tarenych

      это связано с хранением чисел с плавающей точкой, поэтому лучше использовать Decimal.Round(32768.075, MidpointRounding.AwayFromZero) = 32767.08