Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/275.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Mysql或PHP中处理十进制精度_Php_Mysql_Decimal - Fatal编程技术网

在Mysql或PHP中处理十进制精度

在Mysql或PHP中处理十进制精度,php,mysql,decimal,Php,Mysql,Decimal,我有一个MySQL表,即estimate\u item,它包含几个列,这些列包含固定精度的十进制值。这是我的桌子结构 表名:估算项目 在使用PHP检索记录时,我使用MySQL函数进行一些基本计算,我使用的SQL查询如下 SELECT COUNT(ei.item_id) as total_item, SUM(ei.quantity) as total_quantity, SUM(ei.number_of_carton) as total_carton, SUM(


我有一个MySQL表,即
estimate\u item
,它包含几个列,这些列包含固定精度的十进制值。这是我的桌子结构

表名:估算项目

在使用PHP检索记录时,我使用MySQL函数进行一些基本计算,我使用的SQL查询如下

SELECT 
    COUNT(ei.item_id) as total_item,
    SUM(ei.quantity) as total_quantity,
    SUM(ei.number_of_carton) as total_carton,
    SUM(ei.number_of_carton * ei.cbm_per_carton) as total_cbm,
    SUM(ei.quantity * ei.cost) as total_cost,
    SUM(ei.quantity * ei.rate) as total_rate,
    e.commission_amount,
    SUM(ei.quantity * ei.rate) + e.commission_amount as total_amount
FROM
    ai_estimate e
LEFT JOIN
    ai_estimate_item ei ON ei.estimate_id = e.id
WHERE
    ei.estimate_id = ?
例如,上面的查询返回结果

+------------+----------------+--------------+-----------+------------+------------+-------------------+--------------+
| total_item | total_quantity | total_carton | total_cbm | total_cost | total_rate | commission_amount | total_amount |
+------------+----------------+--------------+-----------+------------+------------+-------------------+--------------+
|          2 |            120 |          807 | 1122.6440 |     2.7500 |   137.5000 |           1500.00 |    1637.5000 |
+------------+----------------+--------------+-----------+------------+------------+-------------------+--------------+
由于以下列包含4个精度值
total\u cbm\u total、total\u cost、total\u rate、total\u amount
,因此我想以这种方式对所有四列的值进行取整

a) 如果值为
1122.6440
,则将其四舍五入为
1122.644

b) 如果值为
2.7500
,则将其四舍五入到
2.75

c) 如果值为
137.5000
,则将其四舍五入到
137.50

d) 如果值为
1200.0000
,则将其四舍五入到
1200.00

i、 e我希望这些值至少包含两个精度,根据值的不同,精度可以达到3或4

我有没有办法直接在MySQL中实现这一点?还是PHP方式


感谢并问候。

如果您在MySQL中这样做,我的猜测是您需要在添加一个案例时使查询变得过于复杂。。。结束

所以我会用PHP来实现

function reprecise($value)
{
    $two_digit = number_format($value, 2);
    $three_digit = number_format($value, 3);
    return (float)$two_digit == (float)$three_digit ? $two_digit : $three_digit;
}
这采用了一种技巧——首先计算两位和三位数字的表示,然后检查它们是否是相同的浮点数。如果是,则三位版本的最后一位必须为零,并使用两位版本

要扩展到2、3或4位数,您可以在一个周期内完成:

function reprecise($value)
{
    $digits = 4;
    for ($rep = number_format($value, $digits--); $digits >= 2; $digits--)
    {
            $new = number_format($value, $digits);
            if ($new != $rep)
                    break;
            $rep = $new;
    }
    return $rep;
}
或者,由于字符串函数很可能比数字格式快:

function reprecise($value)
{
    $digits = 9;
    $base   = strrev(number_format($value, $digits));
    for ($i = 0; $i < $digits-2; $i++)
            if ($base[$i] != '0')
                    break;
    return strrev(substr($base, $i));
}
函数重复精度($value)
{
$digits=9;
$base=strev(数字格式($value,$digits));
对于($i=0;$i<$digits-2;$i++)
如果($base[$i]!='0')
打破
返回strev(substr($base,$i));
}

一种方法是使用正则表达式删除小数点后数字末尾的所有
0
,然后用两位小数格式化一个数字,并比较两个结果-返回最长的结果(按字符串)。虽然这可以在mysql中完成,但在php中要容易得多:

//$input - number to format
//$num - minimum number of decimal places to keep
function reformat($input, $num) {
    $parse = preg_replace('/(\.[1-9]*)0+$/', "$1", $input);
    $withmin = number_format($parse, 2); 
    return strlen($withmin) < strlen($parse) ? $parse : $withmin;
}
/$input-要格式化的数字
//$num-保留的最小小数位数
函数重新格式化($input,$num){
$parse=preg\u replace('/(\.[1-9]*)0+$/',“$1”,$input);
$withmin=number\u格式($parse,2);
返回strlen($withmin)
在数据库端,注意cost、rate和cmb\u per\u carton列的尾随0的数量是由表结构预定义的,在您的示例中是40:

cost DECIMAL 19,4
rate DECIMAL 19,4
cmb_per_carton DECIMAL 19,4
如果对这些字段进行操作,结果自然会有相同的尾随0

PHP方面,我刚刚破解了一个简单的函数,它将完成您想要的功能:

function getDecimalFormatted($value, $minPrecision) {
    $value = (float) $value;
    return ((round((($value - floor($value))*pow(10, 5)))%1000) > 0) ? $value : number_format($value, $minPrecision, '.', '');
}
用法示例:

$value = "1234.71200";
echo getDecimalFormatted($value, 2)."\n<br>";

$value = "1234.70000";
echo getDecimalFormatted($value, 2)."\n<br>";

根据您给出的示例,您所要做的就是截断尾随的零。如果您想在PHP中输出它们,可以使用字符串操作或数字格式函数。如果此时我有值
1200.0000
,则截断尾随的零可能会有问题。我希望有两个尾随的零,以便值应该是
1200.00
,不是吗?这是一个很好的方法。当然,随着最大小数位数的增加,它会变得越来越复杂。实际上,OP是处理小数点后2、3或4位的。如果你推断到,比如说小数点后2到10位之间的任何地方,这将变得有点可怕。现在编辑答案。一种更有效的方法是生成最大长度的字符串,然后strev()将其删除,并开始删除最多($digits-2)个连续零,然后再次strev()将其删除。哦,我想我的速度不够快。检查我的版本,我认为我的(几乎)一行是整洁的:)
1234.712
1234.70