在PHP中有一个名为floor()的陷阱
我在AGC019的A题上失败了。
作为问题,
0.25リットルのジュースはQ円、
0.5リットルのジュースはH円、
1リットルのジュースはS円、
2リットルのジュースはD円。
ぴったりNリットルのジュースが欲しい場合、
一番安い組み合わせで買ったらいくらになりますか?(意訳)
ただし、Q、H、S、D、Nはすべて整数とする。
這是一件事情。
以N为整数,我们将计算出最便宜的1升物品。具体来说:
LITTER_1 = min(Q * 4, H * 2, S)
这样子啦。
然后,接下来是要比较2升和1升的单位价格来进行计算的,就是这个流程。
其中,不知何故不能正常运行的代码部分的节选如下。
<?php
$litter1 = 99999995;
$litter2 = 99999997;
$question = 999999999;
// 1リッターが2つの方が高くつく場合
if ($litter1 * 2 > $litter2) {
// 問題が偶数の場合
if ($question % 2 == 0) {
printf("%d\n", $question / 2 * $litter2);
} else {
printf("%d\n", floor($question / 2) * $litter2 + $litter1);
}
} else {
printf("%d\n", $question * $litter1);
}
但是正确答案是49999998499999998。

当我试着执行时,感觉有点偏差。

为什么呢?思考着,仔细观察后,我感到惊讶。
$step1 = floor($question / 2);
printf("[1]%d\n", $step1);
printf("[2]%s\n", gettype($step1));
$step2 = $step1 * $litter2;
printf("[3]%d\n", $step2);
printf("%d\n", floor($question / 2) * $litter2 + $litter1);

将999999999除以2,使用底数函数进行舍去,得出499999999。[1]
这没问题。
然后将其乘以99999997……根据[3]的描述,显然是错误的。499999999 × 99999997不可能以这样多的0结尾。
当检查[1]时,发现变量的类型是double。[2]
在这个时点上,有些不对劲。使用了 floor 函数进行了截断。本应该得到整数,为什么是 double 呢?
根据说明书,
返回不超过 value 的最大整数值(以 float 类型表示)。
为什么是 float 类型呢?
这是因为 float 的范围比 int 更广。
……???
我有点搞不清楚你在说什么,但由于以浮点数的形式返回,我们无法得到正确的数。
我们可以将其转换为(int),但我们先定义一个返回整数类型的函数。
function ifloor($value) {
return intval($value);
}
通过这样做,我们能够得到正确的值。

總結
使用floor或ceil时,最好每次都将其转换为整数类型。
哎呀,竟然隐藏着这样的陷阱……