我已经翻遍了,找不到这个答案。
MySQL 有多少个实际数字FLOAT
?
我知道(想?)它会截断超出FLOAT
4 字节限制的内容,但那到底是什么?
我已经翻遍了,找不到这个答案。
MySQL 有多少个实际数字FLOAT
?
我知道(想?)它会截断超出FLOAT
4 字节限制的内容,但那到底是什么?
从手册(强调我的):
对于 FLOAT,SQL 标准允许在括号中的关键字 FLOAT 之后以位为单位对精度(但不是指数范围)进行可选规范。MySQL 也支持这个可选的精度规范,但精度值仅用于确定存储大小。从0 到 23的精度会产生一个 4 字节的单精度 FLOAT 列。从 24 到 53 的精度会产生一个 8 字节的双精度 DOUBLE 列。
因此,23
尾数的最高精度可以存储在 FLOAT 中,这相当于大约 7 个十进制数字,因为 2^23 ~ 10^7(8,388,608 对 10,000,000)。我在这里测试过。可以看到返回了 12 位十进制数字,其中只有前 7 位是真正准确的。
对于那些认为 MySQL 将浮点数视为与例如 JAVA 相同的人,我得到了一些令人震惊的消息:MySQL 降低了浮点数的可用精度,以便向您隐藏可能不正确的小数位!看一下这个:
爪哇:
public static void main(String[] args) {
long i = 16777225;
DecimalFormat myFormatter = new DecimalFormat("##,###,###");
float iAsFloat = Float.parseFloat("" + i);
System.out.println("long i = " + i + " becomes " + myFormatter.format(iAsFloat));
}
输出是
long i = 16777225 becomes 16,777,224
到目前为止,一切正常。我们的示例整数刚好高于 2^24 = 16777216。由于 23 位尾数,介于 2^23 和 2^24 之间,浮点数可以容纳每个整数。然后从 2^24 到 2^25,它只能容纳偶数,从 2^25 到 2^26 只能容纳能被 4 整除的数字,依此类推(反之亦然:从 2^22 到 2^23,它可以容纳 0.5 的所有倍数)。只要指数没有超出范围,这就是浮点数可以存储的规则。
16777225 是奇数,所以“浮点版本”是一个选项,因为在该范围内(从 2^24 到 2^25),浮点的“步长”为 2。
现在,MySQL 是如何做到的。
这是小提琴,以防你不相信我(我不会)
http://www.sqlfiddle.com/#!2/a42e79/1
CREATE TABLE IF NOT EXISTS `test` (
`test` float NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `test`(`test`) VALUES (16777225)
SELECT * FROM `test`
结果:
16777200
结果是 25 而不是 1,但具有可被 100 整除的“优势”。非常感谢。
我想我理解这种胡说八道背后的“哲学”,但我不能说我赞成。这里是“原因”:
他们不希望您看到可能错误的小数位,他们通过将“实际”浮点值(如在 JAVA 中并根据行业标准)四舍五入到某个合适的 10 次方来实现。
在这个例子中,如果我们保持原样,最后一个数字是错误的,不是零,我们不能这样。
然后,如果我们四舍五入到十的倍数,正确的值将是 16777230,而“实际”浮点数将四舍五入为 16777220。现在,第 7 位是错误的(以前没有错,但现在错了。 ) 而且它不是零。我们不能这样。更好地舍入到 100 的倍数。现在正确的值和“实际”浮点值都舍入到 16777200。所以你只能看到 6 个正确的数字。您不想知道末尾的“24”,告诉您(因为该范围内的步长为 2)您的原始数字必须在 1677723 和 1677725 之间。不,您不想知道; 这两个数字在舍入到第 7 位后在第 7 位上有所不同,因此您无法知道“正确的”第 7 位,因此您想停在第 6 位。反正,
所以他们的目标是四舍五入到一些十进制数字(即6),这样这6位数字总是“正确的”,因为如果你四舍五入原来的确切数字,你会得到相同的6位数字(之前将其转换为浮点数)为 6 位数。而且由于 log_base10(2^23) = 6.92,向下舍入 6,我明白为什么他们认为这将始终有效。可悲的是,这甚至不是真的。
例子:
我 = 33554450
这个数字在 2^25 和 2^26 之间,所以它的“浮动版本”(即 JAVA 浮动版本,而不是 MySQL 浮动版本)是最接近 4 的倍数(较小的那个,如果它在中),所以是
i_as_float = 33554448
我四舍五入到 6 位小数(即 100 的倍数,因为它是一个 8 位数字)给出 33554500。
i_as_float 四舍五入到 6 位小数给出 33554400
哎呀!那些在第 6 位不同!但是不要告诉 MySQL 的人。他们可能刚刚开始将 16777200 “改进”为 16777000。
更新
其他数据库不会那样做。