Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Форумы портала PHP.SU :: Версия для печати :: Формат денег в mysql (decimal)
Форумы портала PHP.SU » » Вопросы новичков » Формат денег в mysql (decimal)

Страниц (3): [1] 2 3 »
 

1. nepster - 09 Августа, 2013 - 13:51:43 - перейти к сообщению
Выбрал для денежных операций тип данных decimal.


Начал проверять, все работает, за исключением 1 момента:

PHP:
скопировать код в буфер обмена
  1.        
  2. $money1 = 213.99999;
  3. $money2 = 283;
  4.  
  5. $money = $money1 + $money2; // результат 496.99999
  6.  


пишем в базу, и туда попадает 497.0000, вот это полное кидалово.
Тип данных в mysql decimal(19,4) DEFAULT NULL

Подскажите пожалуйста как сделать так, что бы в базу записывалось значение без округлений
2. eai - 09 Августа, 2013 - 13:54:33 - перейти к сообщению
Округли записываемое значение до точности колонки.

round($data, 4, PHP_ROUND_HALF_DOWN)

ну или точность колонке на мускле увеличь до 5ти знаков
3. VestCoastman - 09 Августа, 2013 - 13:55:13 - перейти к сообщению
Пользуйтесь DOUBLE(19,4)
4. Мелкий - 09 Августа, 2013 - 13:55:30 - перейти к сообщению
nepster пишет:
decimal(19,4)

nepster пишет:
213.99999

хм. А чему вы удивляетесь?
(Добавление)
VestCoastman, деньги в форматах с плавающей запятой хранить нельзя.
5. nepster - 09 Августа, 2013 - 14:05:18 - перейти к сообщению
подскажите пожалуйста как нужно хранить денежные значения, таким образом, что бы не терялись копейки ?

Цитата:

Округли записываемое значение до точности колонки.

round($data, 4, PHP_ROUND_HALF_DOWN)

ну или точность колонке на мускле увеличь до 5ти знаков


Возвращает 497.

5 знаком или 7, в любом случае иногда будут такие моменты когда будет непонятное-кол знаком после точки. При вычислении % или каких-либо операций
6. eai - 09 Августа, 2013 - 14:23:32 - перейти к сообщению
Да чета раунд глючит ... мож проблема и в прокладке ...

Как решение
$money = ((int)($money*10000))/10000;

Да и осторожно при формировании выражения SQL, не знаю каким методом вы его формируете.
7. DlTA - 09 Августа, 2013 - 14:38:40 - перейти к сообщению
eai пишет:
Как решение
$money = ((int)($money*10000))/10000;
нет, это не решение

а деньги хранят в целочисленному количестве копеек (ну или что у вас там минимальная единица расчета)
8. Мелкий - 09 Августа, 2013 - 14:49:54 - перейти к сообщению
nepster пишет:
будут такие моменты когда будет непонятное-кол знаком после точки. При вычислении % или каких-либо операций

То вам и нужно округлять куда-нибудь до необходимой точности.

nepster пишет:
Возвращает 497.

Разумеется. А что не так? 496.99999 с округлением до 4 знаков после запятой и должно быть 497.
9. eai - 09 Августа, 2013 - 14:51:41 - перейти к сообщению
DlTA пишет:
eai пишет:
Как решение
$money = ((int)($money*10000))/10000;
нет, это не решение

а деньги хранят в целочисленному количестве копеек (ну или что у вас там минимальная единица расчета)


Почему не решение, Реально интересно.

А насчет вашего решения , то я бы так и сделал, но вопрос насколько много уже кода и как много надо переделывать.

По уму надо бы специальный тип данных, аля "С фиксированной запятой"
10. nepster - 09 Августа, 2013 - 14:58:36 - перейти к сообщению
Собственно как вам такое решение:


PHP:
скопировать код в буфер обмена
  1.            
  2.         $money1 = 213.99999;
  3.         $money2 = 283;
  4.        
  5.         $money = $money1 + $money2; // результат 496.99999
  6.        
  7.         $money = $this->my_number_format($money);
  8.        
  9.  
  10.        if(is_numeric($money))
  11.        {
  12.             echo $money; // 496.9999
  13.            
  14.             Yii::app()->db->createCommand()->update('t3', array(
  15.                 'd'=>$money,
  16.             ));
  17.        }



Все проходит как нужно, теперь функция:

идем на php.net
http://www.php.net/manual/ru/fun...format.php#91047

и немного подстраиваем данную функцию

PHP:
скопировать код в буфер обмена
  1.     function my_number_format($number, $dec_point = '.')
  2.     {
  3.         $was_neg = $number < 0; // Because +0 == -0
  4.         $number = abs($number);
  5.    
  6.         $tmp = explode('.', $number);
  7.         $out = number_format($tmp[0], 0, $dec_point, '');
  8.        
  9.        
  10.         if (isset($tmp[1]))
  11.         {
  12.                
  13.             $rest = $dec_point.substr($tmp[1],0,4);
  14.             $out .= $rest;
  15.         }
  16.    
  17.         if ($was_neg) $out = "-$out";
  18.    
  19.         return $out;
  20.     }




работает как нужно! Вопрос только на сколько корректно будет работать с данным методом
11. DlTA - 09 Августа, 2013 - 15:02:14 - перейти к сообщению
eai пишет:
Почему не решение, Реально интересно.
он не помню как я на это попадал, но точность подобных вычислений оставляла желать лучшего
12. eai - 09 Августа, 2013 - 15:02:27 - перейти к сообщению
nepster пишет:
function my_number_format($number, $dec_point = '.')


Попахивает бесовщиной Улыбка
13. DlTA - 09 Августа, 2013 - 15:04:11 - перейти к сообщению
nepster пишет:
  function my_number_format($number, $dec_point = '.')
    {
        $was_neg = $number < 0; // Because +0 == -0
        $number = abs($number);
   
        $tmp = explode('.', $number);
        $out = number_format($tmp[0], 0, $dec_point, '');
       
       
        if (isset($tmp[1]))
        {
               
            $rest = $dec_point.substr($tmp[1],0,4);
            $out .= $rest;
        }
   
        if ($was_neg) $out = "-$out";
   
        return $out;
    }

не смахивает ли это на пятиколесный самокат?
14. nepster - 09 Августа, 2013 - 15:05:23 - перейти к сообщению
Смахивает, и при этом я где-то слышал, что в СССР делали все качественно на совесть =)
(Добавление)
По сути такой момент с 9999 в остатке будет встречаться достаточно редко.

А значит эта функция именно для 2 случаев, если в друг при вычислениях будет момент, когда остаток привысит 4 числа и когда в остатке будет 9999.

Собственно это редкие случаи
15. Мелкий - 09 Августа, 2013 - 15:08:39 - перейти к сообщению
nepster пишет:
на сколько корректно будет работать

Некорректно.
4.00006 должно округляться до 4.0001
1.99997 - до 2
Правила округления давно видели?

Если вам по бизнес-логике нужно округлять в меньшую сторону - floor

 

Powered by ExBB FM 1.0 RC1