php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #74655 parse int and float distort data
Submitted: 2017-05-26 09:47 UTC Modified: 2017-05-26 10:04 UTC
From: an dot nguyen-hoai at lazada dot com Assigned:
Status: Not a bug Package: Math related
PHP Version: 7.0.19 OS: Docker Ubuntu
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: an dot nguyen-hoai at lazada dot com
New email:
PHP Version: OS:

 

 [2017-05-26 09:47 UTC] an dot nguyen-hoai at lazada dot com
Description:
------------
<?php
declare(strict_types=1);

namespace App\Traits;

/**
 * Class SanitizerHelper
 *
 * @package App\Traits
 */
trait SanitizerHelperTrait
{
    /**
     * @param array $data
     * @param array $fields
     *
     * @return array
     */
    public function decimalFormat(array $data, array $fields)
    {
        foreach ($fields as $field) {
            $value = array_get($data, $field, null);
            if ($value) {
                $value        = ((float) $value) * 100;
                $data[$field] = (int) $value;
            }
        }

        return $data;
    }
}


Test script:
---------------
<?php

namespace Tests\Unit\Traits;

use App\SanitizerHelperTrait;

/**
 * Class SanitizerHelperTest
 *
 * @package Tests\Unit\Traits
 */
class SanitizerHelperTest extends \PHPUnit_Framework_TestCase
{
    use SanitizerHelperTrait;

    /**
     * @param $data
     * @param $expected
     *
     * @covers       \App\Traits\SanitizerHelperTrait::decimalFormat()
     * @dataProvider getDecimalDataProvider
     */
    public function test_Decimal_Format($data, $expected)
    {
        static::assertEquals($expected, $this->decimalFormat($data, array_keys($data)));
    }

    public function getDecimalDataProvider()
    {
        return [
            '#1 decimal'    => [
                'data'     => [
                    'discountAmount' => 17.99,
                ],
                'expected' => [
                    'discountAmount' => 1799,
                ],
            ],
            '#2 decimal'    => [
                'data'     => [
                    'arAmount' => 10.02,
                ],
                'expected' => [
                    'arAmount' => 1002,
                ],
            ],
            '#3 decimal'    => [
                'data'     => [
                    'gotAmount' => 10.02,
                ],
                'expected' => [
                    'gotAmount' => 1002,
                ],
            ],
            '#5 No decimal' => [
                'data'     => [
                    'arAmount' => 200,
                ],
                'expected' => [
                    'arAmount' => 20000,
                ],
            ],
            '#6 Null' => [
                'data'     => [
                    'arAmount' => null,
                ],
                'expected' => [
                    'arAmount' => 0,
                ],
            ],
        ];
    }
}

Expected result:
----------------
1799

Actual result:
--------------
1798

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2017-05-26 10:04 UTC] danack@php.net
-Status: Open +Status: Not a bug
 [2017-05-26 10:04 UTC] danack@php.net
Floating point values have a limited precision. Hence a value might 
not have the same string representation after any processing. That also
includes writing a floating point value in your script and directly 
printing it without any mathematical operations.

If you would like to know more about "floats" and what IEEE
754 is, read this:
http://www.floating-point-gui.de/

Thank you for your interest in PHP.

you don't need such a long example:

echo ((int)(17.99 * 100));

output is 1798

Floating point numbers aren't appropriate to store exact values. Writing 17.99 actually gets represented in code as 17.989999771118164 according to https://www.h-schmidt.net/FloatConverter/IEEE754.html

Casting floats to ints rounds down.

Either you should be storing numbers as ints, and then displaying them with the appropriate number of decimal points if they are prices, or you could consider rounding functions.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Wed Nov 06 05:01:28 2024 UTC