MySql 和浮点数或双裁剪我的数字,当我从 php 的每个查询更新它时

MySql and float or double crop my number when I update it per query from php

提问人:TheMAn 提问时间:2/26/2015 更新时间:2/26/2015 访问量:1223

问:

我喜欢使用 InnoDB 以非常精确的方式将纬度和经度存储到我的 MySql 数据库中。但是,float 没有提供足够的内部小数位,所以我切换到 double。有点想知道自己,但 MySql 接受了大小高达 30 的 double,所以我使用了 double(30,27),因为只需要 3 个常规位置,其余的必须在逗号后面。

好吧,在到目前为止有效的 MySql 中,另一方面,我在 json_decode 上收到浮点数,当我回显它们时,逗号后面最多有 18 或 19 个位置。所以即使在这里,一切都如预期的那样。

但是当我构建一个更新查询来填充空的双字段(double 30/27)时,它只是用零填充所有数字,免除前 9 位数字。 或者有时违反规则,从 7 开始。数字,每行 9 秒。

例如,当我在 mysql 中更新 47.2608691999999877 – 无论是每个脚本还是每个 PhpMyAdmin,在点击保存按钮 47.260869199999999000000000000 出现在表格中时,47.26086919999999877000000000000 应该出现或

11.396251100000000633 更新到表中给了我一个 11.396251100000000000000000000

所以看起来它忽略了从 7 开始的可能位置。或者有时用 9 填充它,但在大多数情况下只有零。

任何人都可以给我一个解决这个问题的提示吗?
请记住,我也遇到了 PHPMyAdmin 的问题,但它是由 PHP 组成的。现在我不确定这是MySQL还是PHP问题。

谢谢

例如 我MYSql,我可以很容易地存储它,例如PHPMyAdmin:

php mysql 数据库 浮动精度 sqldatatypes

评论

0赞 PM 77-1 2/26/2015
如果您需要精度 - 使用 .DECIMAL

答:

-1赞 Damian Nikodem 2/26/2015 #1

我不相信任何用于纬度/经度存储的浮点数,您几乎可以保证立即出现舍入错误。浮点数根本不那么准确。

您是否考虑过定点整数 ( 47.2608691999999877 通过乘以和除以 1000000000000000000000000 在需要显示/从输入返回时(甚至只是执行字符串操作进行显示)变得472608691999999877。

这种比例的数字应该相当舒适地适合 64 位整数的范围内(见鬼,你甚至可以得到小数点后 17 位,但仍然可以:P。

评论

0赞 Rick James 2/26/2015
看看我的“答案”,为什么我降级了这个。
0赞 Damian Nikodem 2/26/2015
@RickJamesI只是通读你的答案,关闭但没有雪茄(但实际上你混淆了有效数)我会手动滚动它并使用整数或字符串解析而不是数字解析,甚至存储为字符串(只是为了确保浮点转换不会搞砸它。
0赞 sectus 2/26/2015 #2

您的脚本和 PHPMyAdmin 是在 PHP 上编写的,它使用精度来显示浮点数,但 mysql 和 php 尽可能准确地处理数字。

尝试更改.ini精度设置:http://php.net/manual/ru/ini.core.php#ini.precision

1赞 Rick James 2/26/2015 #3

注意 DOUBLE(30, 27) 对 16-17 位有效数字有意义,然后失控了吗?

FLOAT 具有 24 位精度。这足以容纳大约 7 位有效数字。特别是,对于纬度和经度,这足以精确到 1.7 米(5.6 英尺)以内。对于大多数 lat/lng 应用来说,这已经足够了。因此,插入(从十进制转换为二进制)时存在舍入误差,读取(转换回十进制)时存在另一个错误并不重要。

DOUBLE 有 53 位精度,大约 16 位有效数字 -- 南北向或东西向 3.5 纳米!

DOUBLE(30, 27) -- 当 INSERTing 时,它说 (1) 四舍五入到小数点后 27 位,(2) 四舍五入到 53 位精度。阅读时,它会颠倒步骤,导致你遇到奇怪的混乱。

我从未见过在 FLOAT 或 DOUBLE 上使用 (M,N) 的有效需求。别这样。

For DECIMAL(M,N), you are storing exactly what will fit to N decimal places. For lat/lng purposes, consider DECIMAL(6,4) for latitude and (7,4) for longitude -- 16 meters (52 feet). Or, for more precision, (8,6) and (9,6) -- 16cm (6 inches).

Note further that a FLOAT takes 4 bytes (always), DOUBLE: 8, DECIMAL(6,4): 3, (7,4): 4, (8,6): 4, (9,6): 5. If you have billions of lat/lng entries, the bytes of storage adds up.

评论

0赞 Damian Nikodem 2/26/2015
Due to the fact that it is not really possible to represent every possible lat/long value with 16 digits of accuracy correctly, I would say the correct answer is to move towards a integer based data type (so decimal counts since it is a fixed decimal place) if math is attempted then having differing exponents on numbers can have a massive loss of precision, and in addition to all this due to PHP's dynamic typing this could cause issue in unexpected places. Especially because we fudge numbers for display purposes.
0赞 Rick James 2/26/2015
PHP uses 32-bit integers. Degrees * 10000 can be stored in a MEDIUMINT (3 bytes) and give you 2.7 meter (8.8 ft) resolution. INT would give you less than 10 significant digits. I can't imagine why you feel it necessary to store "16 digits of accuracy", nor can I imagine what system will give you that much precision.
0赞 Damian Nikodem 2/26/2015
PHP integers are platform dependant so on any sane operating system a 64 bit OS means 64 bit signed integers (although the php5.5 documentation states that windows is always considered 32 bit. ) as for that level of in lat/long co-ordinates. I can imagine this resolution being part of a ASTERIX specification.
0赞 Rick James 2/26/2015
Notice how all their values end with a bunch of zeros or 9s or similar indications of displaying more precision than they actually have available. I would suggest that they don't have more than 7 decimal places and that the noise after that is due to sloppiness in their display algorithm. 7 places is tight enough to two marbles.
1赞 Damian Nikodem 2/26/2015
My initial thought would be that there is 6 worth of precision and the rest is rounding error when dealing with floating point.