ф-я округления вещественного числа ???
От: Аноним  
Дата: 04.03.03 05:46
Оценка:
собственно субж,

что-то найти не могу

Заранее спасибо.
Re: ф-я округления вещественного числа ???
От: orangy Россия
Дата: 04.03.03 05:56
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>собственно субж,

А>что-то найти не могу
А школу вспомнить не помогает?

template<typename T> int round(T value) { return int(value + 0.5); }
... << RSDN@Home 1.0 beta 6a | Сейчас вторник, 11:03, слушаю Betray My Secrets — Of Things Not Seen >>
"Develop with pleasure!"
Re[2]: ф-я округления вещественного числа ???
От: Аноним  
Дата: 04.03.03 06:12
Оценка:
Здравствуйте, orangy, Вы писали:

O>Здравствуйте, <Аноним>, Вы писали:


А>>собственно субж,

А>>что-то найти не могу
O>А школу вспомнить не помогает?

O>
O>template<typename T> int round(T value) { return int(value + 0.5); }
O>


O>


а стандартной нету что-ли??
нужно только C, не C++

такое тоже не подходит :

double round_d2d(double fSrc)
{
 char cbBuff[32];
 sprintf(cbBuff, "%3.1f", fSrc);
 return atof(cbBuff);
}


Нужно округление после запятой.

Заранее спасибо.
Re[3]: ф-я округления вещественного числа ???
От: small_cat Россия  
Дата: 04.03.03 06:38
Оценка:
Что значит округление после запятой?
Если просто округление — то есть ф-ции:

#include <math.h> — хедер

double floor(double x) — наибольшее целое, которое меньше или равно x
double ceil(double x) — наименьшее целое, которое больше или равно x

Если тебе нужно округление так, как это обычно понимается, то используй

floor(x+.5)

Успехов.
- Простите, профессор, не пса, а когда он уже был человеком.
— То-есть он говорил? Это еще не значит быть человеком. (с) Булгаков
Re[4]: ф-я округления вещественного числа ???
От: Аноним  
Дата: 04.03.03 06:46
Оценка:
Здравствуйте, small_cat, Вы писали:

SC>Что значит округление после запятой?


это значит :

10.11111 = 10.1
10.56 = 10.6
10.6 = 10.6

SC>Если просто округление — то есть ф-ции:


SC>#include <math.h> — хедер


SC>double floor(double x) — наибольшее целое, которое меньше или равно x

SC>double ceil(double x) — наименьшее целое, которое больше или равно x

SC>Если тебе нужно округление так, как это обычно понимается, то используй


SC>floor(x+.5)


это немного не то, что мне нужно
см. выше
Re[5]: ф-я округления вещественного числа ???
От: Left2 Украина  
Дата: 04.03.03 07:15
Оценка:
А>это немного не то, что мне нужно

Тогда то что тебе нужно это

(int) (x+0.05)
Re[5]: ф-я округления вещественного числа ???
От: Алексей Владимирович Миронов Россия  
Дата: 04.03.03 07:20
Оценка:
Здравствуйте, Аноним, Вы писали:

А>это немного не то, что мне нужно

А>см. выше

#include <stdio.h>
#include <math.h>

#ifndef M_PI
#define M_PI 3.1415926
#endif

double round_up ( double val, unsigned int digits )
{
  return floor (val * pow ( 10.0, digits ) + 0.5) / pow ( 10.0, digits );
}

void main ( void )
{
  int digits;

  for ( digits = 0; digits < 7; digits++ )
    printf ( "%d: %.7f\n", digits, round_up ( M_PI, digits ) );
}


Выдает:

0: 3.0000000
1: 3.1000000
2: 3.1400000
3: 3.1420000
4: 3.1416000
5: 3.1415900
6: 3.1415930
Re[5]: ф-я округления вещественного числа ???
От: Кодт Россия  
Дата: 04.03.03 08:09
Оценка: 93 (8)
Здравствуйте, Аноним, Вы писали:

А>это значит :


А>10.11111 = 10.1

А>10.56 = 10.6
А>10.6 = 10.6

double round(double x, double accuracy)
{
  assert(accuracy > 0);
  return floor(x / accuracy + 0.5) * accuracy;
}

round(10.56, 1.0) = floor(11.06) = 11.0

round(10.56, 0.1) = floor(10.56*10 + 0.5)*0.1 = floor(106.1)*0.1 = 10.6

round(10.56, 0.5) = floor(10.56*2 + 0.5)*0.5 = floor(21.72)*0.5 = 10.5
round(10.76, 0.5) = floor(10.76*2 + 0.5)*0.5 = floor(22.02)*0.5 = 11.0
Перекуём баги на фичи!
Re[6]: ф-я округления вещественного числа ???
От: Кодт Россия  
Дата: 04.03.03 08:15
Оценка:
Здравствуйте, Алексей Владимирович Миронов, Вы писали:

АВМ>
АВМ>double round_up ( double val, unsigned int digits )
АВМ>{
АВМ>  return floor (val * pow ( 10.0, digits ) + 0.5) / pow ( 10.0, digits );
АВМ>}
АВМ>


Функцию pow (тем более — дважды) использовать неэкономно.

Если нужна быстрая реализация, то достаточно вспомнить, что потолок double — это 1.7e308,
следовательно, нужна таблица из 308 значений целых степеней 10.
Перекуём баги на фичи!
Re[6]: Разминка для ума 8-)
От: Рек Россия  
Дата: 05.03.03 13:15
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, Аноним, Вы писали:


К>
К>double round(double x, double accuracy)
К>{
К>  assert(accuracy > 0);
К>  return floor(x / accuracy + 0.5) * accuracy;
К>}
К>


А слабо написать процедуру
сохранения в числе (в любом!) заданного кол-ва десятичных значащих цифр?

Например, надо сохранить в числе 4 значащих цифры.

102.8776 -> 102.9

и в тоже время

0.00001028776 -> 0.00001029
Re[7]: Разминка для ума 8-)
От: _wqwa США  
Дата: 05.03.03 14:13
Оценка:
Здравствуйте, Рек, Вы писали:


Рек>А слабо написать процедуру


Нефик делать

double round(double x, double digits) // digits -- кол-во десятичных знаков, которые надо оставить, 
{
    double intDg=floor(log10(x)+1);
    double acc=pow(10,intDg-digits);

    return floor(x/acc+0.5)*acc;
}
RSDN@Home
Кто здесь?!
Re[8]: Информация для размышления
От: XXXL  
Дата: 22.10.03 12:54
Оценка:
Всем привет!
Для меня тоже оказалась актуальна тема округления.
У меня для вас есть немного вкусненького.
Есть небольшая модификация алгоритма округления до любого
числа знаков после запятой:

double round( double val, unsigned signs ) //[1]
{
double p = pow( 10., signs );
return floor( val * p + .5 ) / p;
}

val — само число,
signs — количество знаков после запятой.

...

Например,

round( 1.15, 1 ) == 1.2;
round( 1.555, 2 ) == 1.56;

Но,

round( 0.285, 2 ) == 0.28; //!!!!!!!!!

Когда должно получиться 0.29!

Исследуя, природу этой ошибки, меня посетила такая мысль.
Что не любое число может быть представлено в формате типа
double. Одним из этих чисел является 0.285, и то что мы
видим 0.285 — это не так. На самом деле число 0.285
представлено числом, близким к нему, это число
0.284(9) ( 9 в периоде ). В доказательство этому привожу
фрагмент кода:

1. double integer;
2. double fractional;
3. fractional = modf( 0.285 * 100., &integer );
4. int iv = (int)( fractional * 100. );

После выполнения строки номер 4 переменная iv принимает значение,
как вы думаете, не 50, а 49!

В результате стал перед проблемой правильного округления.
Если у кого есть соображения по этому поводу, пожалуйста,
высказываейтесь, будет интересно узнать.

Примечание: В компиляторе Borland Pascal 7.0 округление,
вроде корректно со всеми числами. Может все дело в структуре
хранения чисел с плавающей запятой в C?
Re[9]: Информация для размышления
От: Павел Кузнецов  
Дата: 22.10.03 12:58
Оценка:
Здравствуйте, XXXL, Вы писали:

X> Исследуя, природу этой ошибки, меня посетила такая мысль.

X> Что не любое число может быть представлено в формате типа
X> double. Одним из этих чисел является 0.285

Верное наблюдение

X> В результате стал перед проблемой правильного округления.

X> Если у кого есть соображения по этому поводу, пожалуйста,
X> высказываейтесь, будет интересно узнать.

1) Не трогать сами числа, а "округлять" при выводе
2) Перейти на числа с фиксированной точкой
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[10]: Информация для размышления
От: XXXL  
Дата: 22.10.03 13:10
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>1) Не трогать сами числа, а "округлять" при выводе

ПК>2) Перейти на числа с фиксированной точкой

У меня была такая идея, перейти на целые числа, и я
почти добился успеха. Но не могу осмыслить, как понять
что в случае c числом 0.285 0.004(9) — это 0.005? Была
идея определить такое мале число E, которое при сложении
с округляемым его выравнивала, если это число не точное,
и не влияло на результат, если число задано точно. Но
идея была отброшена так как 0.285 — это 0.284(9)6...!
Не отнимет ли у Вас много времени более подробное описание
перехода к числам с фиксированной запятой?
Re[11]: Информация для размышления
От: Павел Кузнецов  
Дата: 22.10.03 13:18
Оценка:
Здравствуйте, XXXL, Вы писали:

ПК>> 1) Не трогать сами числа, а "округлять" при выводе

ПК>> 2) Перейти на числа с фиксированной точкой

X> более подробное описание перехода к числам с фиксированной запятой?


Не очень подробно, но идея, в общем, такая: float/double вообще не используются.
Вместо этого используются целые с достаточным запасом точности (обычно хватает
__int64/long long). Также выбирается какой-то произвольный множитель, определяющий
"позицию" фиксированной десятичной точки/запятой. Для большинства бизнес-приложений
6-8 знаков после точки/запятой вполне достаточно. Для уменьшения количества ошибок
программирования все это, конечно, оборачивается в какие-нибудь классы. Более того:
таких классов, уже готовых, вполне достаточно в Интернете
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[12]: Информация для размышления
От: XXXL  
Дата: 22.10.03 13:24
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Вместо этого используются целые с достаточным запасом точности (обычно хватает

ПК>__int64/long long). Также выбирается какой-то произвольный множитель, определяющий
ПК>"позицию" фиксированной десятичной точки/запятой.

Спасибо за совет! Так действительно решается проблема округления во многих составляющих
элементах бизнес-систем, например в кассовых аппаратах.
Re[12]: Информация для размышления
От: XXXL  
Дата: 23.10.03 14:35
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>...Для уменьшения количества ошибок

ПК>программирования все это, конечно, оборачивается в какие-нибудь классы. Более того:
ПК>таких классов, уже готовых, вполне достаточно в Интернете

Я написал класс-обертку, о котором Вы говорили, для реализации чисел с фиксированой
запятой. Может найдутся желающие его "попинать" или те, кому он может пригодиться ?

Некоторыми моментами в этом коде я остался недоволен , так как не нашел однозначно-правильного
решения . Например, при делении чисел с разной точностью (количество знаков после запятой,
ведь числа с фиксированной запятой) не понятно , какую точность должен иметь результат,
остановился на том, что операцию деления можно выполнять только над числами с одинаковой точностью .
Тоже самое относится к операциям сложения и вычитания. По хорошему надо брать максимальную точность
из двух операндов, но я не смог догадаться как. Может быть препроцессорные диррективы могут
решить эту задачу? А вот при умножении все ясно, точность результата — это сумма точночтей операндов.
И еще одна мелочь, количество символов (22) под строку я выделил из соображения, что количество
цифр в unsigned __int64 не может быть больше 20-ти, и плюс два символа на минус и разделяющую
точку. Символ конца строки учитываю при выделении памяти под строку. Так вот хотелось бы
поинтересоваться , можно ли как-нибудь определить по размеру целого типа максимальное
количество цифр, которое он может представить?

В общем, все. Пинайте на здоровье. Интересно будет послушать ваши мысли.


// file : FixedPoint.h

#pragma once

#include <math.h>
#include <stdio.h>

typedef __int64 VAL_TYPE;

template<unsigned char accuracy, unsigned char sbuf_len = 22>
class FixedPoint
{
public:

    FixedPoint()
    {
        init();
        *this = (VAL_TYPE)0;
    }

    FixedPoint( VAL_TYPE val )
    {
        init();
        *this = val;
    }

    FixedPoint( double val )
    {
        init();
        *this = val;
    }

    template<unsigned char T>
    FixedPoint( const FixedPoint<T> & obj )
    {
        init();
        *this = obj;
    }

    inline unsigned char get_accuracy() const
    {
        return accuracy;
    }

    inline VAL_TYPE get_mult() const
    {
        return _mult;
    }

    inline VAL_TYPE get_val() const
    {
        return _val;
    }

    inline VAL_TYPE get_abs_val() const
    {
        return _val * get_sign();
    }

    inline double get_double() const
    {
        return ((double)_val) / ((double)_mult);
    }

    inline const char * get_str( char separator = '.' )
    {
        return get_str( _str, separator );
    }

    inline char * get_str( char * buf, char separator = '.' )
    {
        sprintf(
            buf,
            "%.0f%c%.0f",
            (double)( _val / _mult ),
            separator,
            (double)( _val % _mult * get_sign() ));
        return buf;
    }

    inline VAL_TYPE get_sign() const
    {
        return get_sign( _val );
    }

    template<class T>
    inline static T get_sign( T val )
    {
        return (T)( val < (T)0 ? -1 : 1 );
    }

    template<unsigned char T>
    inline FixedPoint<accuracy + T> operator * ( const FixedPoint<T> & obj ) const
    {
        return FixedPoint<accuracy + T>( _val * obj.get_val() );
    }

    template<unsigned char T>
    inline FixedPoint<accuracy> & operator *= ( const FixedPoint<T> & obj )
    {
        *this = *this * obj;
        return *this;
    }

    template<unsigned char T>
    inline FixedPoint<accuracy> operator + ( const FixedPoint<T> & obj )
    {
        return FixedPoint<accuracy + T>( _val + obj._val );
    }

    inline FixedPoint<accuracy> & operator += ( const FixedPoint<accuracy> & obj )
    {
        *this = *this + obj;
        return *this;
    }

    inline FixedPoint<accuracy> operator - ( const FixedPoint<accuracy> & obj )
    {
        return FixedPoint<accuracy>( _val - obj._val );
    }

    inline FixedPoint<accuracy> & operator -= ( const FixedPoint<accuracy> & obj )
    {
        *this = *this - obj;
        return *this;
    }

    FixedPoint<accuracy> operator / ( const FixedPoint<accuracy> & obj )
    {
        VAL_TYPE obj_val = obj.get_abs_val();
        VAL_TYPE loc_val = get_abs_val();
        VAL_TYPE v = loc_val / obj_val;
        VAL_TYPE dr = loc_val % obj_val;
        for( int i = 0; i < accuracy + 1; i++ )
        {
            dr *= 10;
            v = v * 10 + dr / obj_val;
            dr = dr % obj_val;
        }
        return FixedPoint<accuracy + 1>( v * get_sign() * obj.get_sign() );
    }

    template<unsigned char T>
    inline FixedPoint<accuracy> & operator = ( const FixedPoint<T> & obj )
    {
        _val = obj.get_val();
        if( accuracy < T )
        {
            VAL_TYPE md = obj.get_mult() / _mult;
            _val = _val / md + (( obj.get_abs_val() % md < 5 ) ? 0 : obj.get_sign() );
        }
        else if( accuracy > T )
            _val *= _mult / obj.get_mult();

        return *this;
    }

    inline FixedPoint<accuracy> & operator = ( VAL_TYPE val )
    {
        _val = val;
        return *this;
    }

    inline FixedPoint<accuracy> & operator = ( double val )
    {
        _val = (VAL_TYPE)floor( fabs( val ) * _mult + .5 );
        _val *= get_sign( val );
        return *this;
    }

private:

    void init()
    {
        _mult = (VAL_TYPE)pow( 10., accuracy );
    }
    
private:
    
    VAL_TYPE    _val;
    VAL_TYPE    _mult;
    char        _str[ sbuf_len + 1 ];
};
Re[13]: Информация для размышления
От: Кодт Россия  
Дата: 24.10.03 11:44
Оценка:
Здравствуйте, XXXL, Вы писали:

XXX>Я написал класс-обертку, о котором Вы говорили, для реализации чисел с фиксированой

XXX>запятой. Может найдутся желающие его "попинать" или те, кому он может пригодиться ?

Пока не удалил — попинаю.

Поскольку у тебя VAL_TYPE является внутренним представленим — то, имхо, не стоит делать конструктор с параметром VAL_TYPE. Или хотя бы сделать его explicit — чтобы избежать ошибок.

Незачем хранить value и mult. Так ты просто получаешь все ту же плавающую арифметику...

Имхо, можно проще.
template<int A> // A = 1/accuracy. То есть 0.001 --> 1000
class FixedPoint
{
public:
  typedef _int64 value_t;
  typedef FixedPoint<A> self_t;

private:
  value_t v_;

public:
  value_t value() const { return v_; }

  value_t floor() const { return v_ / A; }
  value_t ceil() const { return (v_+A-1) / A; }
  value_t round() const { return (v_+A/2) / A; }

  value_t frac() const { return v_ % A; }

  double dbl() const { return double(v_) / A; }

  operator value_t() const { return round(); }
  operator double() const { return dbl(); }


  FixedPoint(int v) : v_(v * A) {}

  template<int B>
  FixedPoint(const FixedPoint& v) : v_(v.value() * A/B) {}

  FixedPoint(double v) : v_(v * A) {}

  // все остальные - только со своим типом. Чужие типы - через имплицитные конструкторы

  self_t& operator = (const self_t& v) { v_ = v.value(); return *this; }
  self_t& operator += (const self_t& v) { v_ += v.value(); return *this; }
  self_t& operator -= (const self_t& v) { v_ += v.value(); return *this; }

  self_t& operator *= (const self_t& v) { v_ = v_ * v.value() / A; return *this; }
  self_t& operator /= (const self_t& v) { v_ = v_ * A / v.value(); return *this; }
};

template<int A, class T>
FixedPoint<A> operator + (FixedPoint<A> const& x, const T& y) { FixedPoint<A> z(x); z += y; return z; }
// и т.п.
// или можешь затащить их в члены класса.

template<int A>
int floor(const FixedPoint<A>& v) { return v.floor(); }

template<int A>
int ceil(const FixedPoint<A>& v) { return v.ceil(); }

template<int A>
int frac(const FixedPoint<A>& v) { return v.frac(); }

template<int A>
int round(const FixedPoint<A>& v) { return v.round(); }
Перекуём баги на фичи!
Re[6]: ф-я округления вещественного числа ???
От: Димчанский Литва http://dimchansky.github.io/
Дата: 20.07.04 10:55
Оценка: 4 (1)
Здравствуйте, Кодт, Вы писали:

К>
К>double round(double x, double accuracy)
К>{
К>  assert(accuracy > 0);
К>  return floor(x / accuracy + 0.5) * accuracy;
К>}
К>


Я бы переписал код так:
double round(double x, double accuracy)
{
  assert(accuracy > 0);
  if(x<0)
    return ceil(x / accuracy - 0.5) * accuracy;
  return floor(x / accuracy + 0.5) * accuracy;
}

Так как в противном случае возникает неопределенность:
round(-1.5, 1.0) = -1.0 (должно бы получиться -2.0)
в то время как
round(1.5, 1.0) = 2.0

В MatLab round работает "одинаково" как для отрицательных чисел, так и для положительных.
Re[7]: ф-я округления вещественного числа ???
От: jazzer Россия Skype: enerjazzer
Дата: 21.07.04 11:40
Оценка:
Здравствуйте, Димчанский, Вы писали:

Д>Здравствуйте, Кодт, Вы писали:


К>>
К>>double round(double x, double accuracy)
К>>{
К>>  assert(accuracy > 0);
К>>  return floor(x / accuracy + 0.5) * accuracy;
К>>}
К>>


Д>Я бы переписал код так:

Д>
Д>double round(double x, double accuracy)
Д>{
Д>  assert(accuracy > 0);
Д>  if(x<0)
Д>    return ceil(x / accuracy - 0.5) * accuracy;
Д>  return floor(x / accuracy + 0.5) * accuracy;
Д>}
Д>

Д>Так как в противном случае возникает неопределенность:
Д>round(-1.5, 1.0) = -1.0 (должно бы получиться -2.0)
Д>в то время как
Д>round(1.5, 1.0) = 2.0

Д>В MatLab round работает "одинаково" как для отрицательных чисел, так и для положительных.


неправильно работает

по определению операции округления, действительное число округляется до целого х, если оно попадает в [x-0.5, x+0.5), независимо от знака.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.