Ru-Board.club
← Вернуться в раздел «Прикладное программирование»

» Округление в C++ Builder

Автор: Dimka2003
Дата сообщения: 21.03.2003 22:35
Подскажите, плз, как сделать граммотное округление....

Вариант умножения на 10 в степени N (точность округления), затем отброс дробной части (или функция округления), а затем деление на 10^N не годится, так как после деления в результате остается хвостик, типа:
3.1415925
N=2

В результате: floor(3.1415926*pow(10, 2))/pow(10, 2)=3.140000000012

Как можно этого избежать?
Автор: JeanM
Дата сообщения: 21.03.2003 23:09
Dimka2003
txtItogo->Text = FloatToStrF(StrToFloat(txtItogo->Text),ffNumber,15,2)

про эту функцию посмотри подробнее в помощи, потому как
ffNumber - формат, вроде :)
15 - значение, отвечающее за размер числа (в байтах), вроде :)
2 - число знаков после зпт
короче, вот так оно работает, а что там еще есть я уже давно забыл :)

Автор: Atreidies
Дата сообщения: 21.03.2003 23:21
Если правильно понял вопрос, то в С++ Builder:


Код:
#include "Math.hpp"
...
double result = SimpleRoundTo(3.1415925, -2);
// result will be 3.14

Автор: Dimka2003
Дата сообщения: 22.03.2003 09:46

Цитата:
JeanM:
txtItogo->Text = FloatToStrF(StrToFloat(txtItogo->Text),ffNumber,15,2)


К сожалению этот вариант не работает... Если после этого получить float Itogo=StrToFloat(txtItogo->Text) и посмотреть его значение в watch, то оно будет как раз таки с "хвостиком" в 1/100000....



Цитата:
Atreidies

Код: #include "Math.hpp"
...
double result = SimpleRoundTo(3.1415925, -2);
// result will be 3.14
Автор: Dust
Дата сообщения: 22.03.2003 10:10
Dimka2003
Сделай серч по диску, а?
Автор: Atreidies
Дата сообщения: 24.03.2003 12:26
Dimka2003

Цитата:
У меня Borland C++ Builder 5....

Сегодня посмотрел - в 5 ее нет и, в целом, достаточно сильно изменился Math.hpp

попробуй следующее:


Код:
int digits = -2;
double value = 3.1465925;
double lfactor = IntPower(10, digits);
double result = int((value / lfactor) + 0.5) * lfactor;
Автор: vserd
Дата сообщения: 25.03.2003 09:21
Dimka2003

Цитата:
Если после этого получить float Itogo=StrToFloat(txtItogo->Text) и посмотреть его значение в watch, то оно будет как раз таки с "хвостиком" в 1/100000

Значит это такая судьба мучаться с вещественными числами. Скорей всего это число нельзя представить по другому в машинном представлении.
Если это работа с деньгами, то как вариант приводи к целому (* 100), округляй, суммируй целые и дели на 100.
Еще вариант взять вещественый тип большей точности чем используешь сейчас.
И еще один :) при работе не допускай возникновения таких дробей (переодически округляй).
Автор: kingiv
Дата сообщения: 19.03.2009 10:15
софтину пишу, проманался мин 40.
там есть така формула, рез-тат перемножения округлить до 2 знака после зпт.
119.99*2.5=299.975 (калькулятор)
Округл. неверно: 299.97 вместо 299.98.
Тупо не догонял почему пока не плюнул и не протрассировал пошагово:

float fd=2.5*119.99;
double dd=2.5*119.99;
ShowMessage(as.sprintf("float fd=2.5*119.99=%f\ndouble dd=2.5*119.99=%f",fd,dd));

рез-т:

fd=119.99*2.5=299.975006
dd=119.99*2.5=299.974995

в итоге эта сука таки правильно округляла... Но! только для типа float...
ненавижу!

Вывод: хочешь правильно округлить, округляй 2 раза... Гы-ы.
Первый раз до нужного+1 знака после зпт., второй раз уже округл. значение до нужного знака после зпт.
Автор: veronica b
Дата сообщения: 19.03.2009 23:14

Цитата:
В результате: floor(3.1415926*pow(10, 2))/pow(10, 2)=3.140000000012

Как можно этого избежать?

Никак! Произошло правильное округлеие и получили правильный результат 3.14!
А 3.140000000012 это как компьютер представляет это число.
Автор: 2nd
Дата сообщения: 21.03.2009 18:30
для бухгалтерских задач лучше писать свою функцию округления
Автор: veronica b
Дата сообщения: 21.03.2009 19:55

Цитата:
для бухгалтерских задач лучше писать свою функцию округления

Для такого типа задач не стоит использовать плавающую точку, а использовать фиксированную точку и тип long. Конечно, если есть большие вычисления.
Автор: kingiv
Дата сообщения: 02.07.2010 14:57
На тот момент наваялось вот такое... Не претендует на скорость.
//d=197.97499 fc=197 fd=97499 p=2
//return "197.98"
AnsiString RoundMy(double d, int p)
{ int t; long fc,fd,pp;

pp=pow(10,p);
fc=(long)d;
fd=(long)((d-fc)*1000000000);
for(int i=1;i<9;i++)
{ t=fd - 10*(long)(fd/10);
fd=(long)(fd/10);
if(t>4)fd+=1;
if(fd<pp)break;
}
return IntToStr(fc)+"."+IntToStr(fd);
}
Автор: Dmitry46
Дата сообщения: 30.06.2011 02:03
вот такая функция с использованием только стандартных возможностей C++ Builder
double RoundDouble(double d, int p)
{
int buf = 1;
for(int i=0;i<p;i++) buf*=10; // это чтобы не использовать math и pow в частности
__int64 i=(int)(d*buf*10);
if(i%10>=5) i=i/10+1;
else i/=10;
double dnew = i;

return dnew/buf;
}
Автор: Tantos
Дата сообщения: 05.07.2011 01:29
Варианты реализаций:
[more]

Код:
//---------------------------------------------------------------------------
static double Round(double op)
{
return floor(op + 0.5);
}
//---------------------------------------------------------------------------
double Round(double Value, int Digits)
{
double Int = 0.0,
Fract;
int i;

Fract = modf (Value, &Int);
for (i = 0; i < Digits; i++)
Fract *= 10.0;
Fract += 0.5;
Fract = double (floor(Fract));
for (i=0; i<Digits; i++)
Fract /= 10.0;

return Int+Fract;
}
//-------------------------------------------------------------
static double Round(double op, double pow)
{
if (pow <= 0.) return op;
if (op>0. && op<pow || op<0. && op>pow) return 0.;
op = floor(op/pow + 0.5) * pow;
return op>0. && op<pow || op<0. && op>pow? 0.: op;
}
//-------------------------------------------------------------
double Round1(double Argument, int Precision)
{
double div = 1.0;
if(Precision >= 0) {
while(Precision--)
div *= 10.0;
}
else {
while(Precision++)
div /= 10.0;
}
return floor(Argument * div + 0.5) / div;
}
//-------------------------------------------------------------
double Round2(double Value, int Digits)
{
double Int = 0.0,
Fract;
int i;

Fract = modf (Value, &Int);
for (i = 0; i < Digits; i++)
Fract *= 10.0;

Fract = double (floor(Fract));
for (i=0; i<Digits; i++)
Fract /= 10.0;

return Int+Fract;
}
//-------------------------------------------------------------

Страницы: 1

Предыдущая тема: Программирование DirectSound на Delphi


Форум Ru-Board.club — поднят 15-09-2016 числа. Цель - сохранить наследие старого Ru-Board, истории становления российского интернета. Сделано для людей.