답변:
이것이 내가 의심했을 때 찾은 것입니다.
mysql> create table numbers (a decimal(10,2), b float);
mysql> insert into numbers values (100, 100);
mysql> select @a := (a/3), @b := (b/3), @a * 3, @b * 3 from numbers \G
*************************** 1. row ***************************
@a := (a/3): 33.333333333
@b := (b/3): 33.333333333333
@a + @a + @a: 99.999999999000000000000000000000
@b + @b + @b: 100
십진수는이 경우에해야 할 일을 정확하게 수행했으며 나머지는 잘랐으므로 1/3 부분을 잃었습니다.
따라서 합계의 경우 소수점이 더 좋지만 나누기의 경우 부동 소수점이 더 좋습니다. DECIMAL을 사용해도 "실패한 산술"은 제공되지 않습니다.
도움이 되었기를 바랍니다.
@a
99.999999999000000000000000000000에 DECIMAL을 제공 하지 않습니까? 기술적으로 맞습니다.
대부분의 환경에서 "부동"은 이진 부동 소수점 유형입니다. 기본 2 값을 특정 지점까지 정확하게 저장할 수 있지만 많은 10 기본 (10 진수) 값을 정확하게 저장할 수는 없습니다. 실수는 과학적 계산에 가장 적합합니다. 그들은 것 없는 대부분의 비즈니스 중심의 수학에 대한 적절한, 그리고 수레의 부적절한 사용은 물린 것입니다. 많은 10 진수 값은 밑이 2로 정확하게 표현 될 수 없습니다. 0.1
예를 들어, 할 수 없으므로와 같은 이상한 결과가 나타납니다 1.0 - 0.1 = 0.8999999
.
소수는 10 진수를 저장합니다. 10 진수는 대부분의 비즈니스 수학에 적합한 유형입니다 (그러나 기본 제공 "돈"유형은 재무 계산에 더 적합합니다). 여기서 값의 범위는 정수 유형이 제공하는 범위를 초과하고 분수 값이 필요합니다. 이름에서 알 수 있듯이 10 진법은 10 진법으로 설계되었습니다. 10 진법 값을 특정 지점까지 정확하게 저장할 수 있습니다.
MySQL은 최근에 DECIMAL 유형 을 저장하는 방식을 변경했습니다 . 과거에는 숫자 대 2의 보수 정수 또는 그 파생어에 대한 ASCII (또는 nybble) 표현을 포함하는 각 숫자에 대한 문자 (또는 nybbles)를 저장했습니다.
DECIMAL의 현재 저장 형식은 일련의 1,2,3 또는 4 바이트 정수이며, 비트는 연결되어 사용자가 정의한 암시 적 소수점으로 2의 보수 수를 생성하고 선언 할 때 DB 스키마에 저장됩니다. 열을 선택하고 DECIMAL 크기와 소수점 위치를 지정하십시오.
예를 들어, 32 비트 정수를 사용하는 경우 0-4,294,967,295의 숫자를 저장할 수 있습니다. 그것은 단지 999,999,999를 확실히 커버 할 것이므로 2 비트를 버리고 (1 << 30-1) 사용하면 아무것도 포기하지 않을 것입니다. 4 바이트만으로 9 자리 숫자를 모두 처리하는 것은 4 개의 ASCII 문자 또는 8 개의 니블 숫자를 사용하여 32 비트로 4 자리를 처리하는 것보다 효율적입니다. (nybble은 4 비트이므로 0 ~ 9에 필요한 것보다 많은 0 ~ 15 값을 허용하지만 0 ~ 7의 값만 포함하므로 3 비트로 이동하여 낭비를 제거 할 수 없음)
MySQL 온라인 문서에서 사용 된 예는 DECIMAL (18,9)을 예로 사용합니다. 암시 적 소수점 뒤에 9 자리 앞뒤 9 자리이며 위에 설명 된대로 다음 저장 공간이 필요합니다.
18 개의 8 비트 문자 : 144 비트
18 비트 4 비트 니블 : 72 비트
2 개의 32 비트 정수 : 64 비트
현재 DECIMAL은 허용 된 M의 최대 값이 65이고 D의 최대 값이 30 인 DECIMAL (M, D)로 최대 65 자리를 지원합니다.
한 번에 9 자리의 청크가 필요하지 않도록 32 비트보다 작은 정수는 1, 2 및 3 바이트 정수를 사용하여 숫자를 추가하는 데 사용됩니다. 어떤 이유로 논리를 무시하고 부호없는 정수 대신 부호있는 부호가 사용되어 1 비트가 발생하여 다음과 같은 저장 기능이 제공됩니다. 1,2 및 4 바이트 정수의 경우 손실 된 비트는 중요하지 않지만 3 바이트 정수의 경우 단일 비트의 손실로 인해 전체 숫자가 손실되므로 재앙입니다.
7 비트 정수로 : 0-99
15 비트 정수로 : 0-9,999
23 비트 정수로 : 0-999,999 (24 비트 정수로 0-9,999,999)
1,2,3 및 4 바이트 정수는 함께 연결되어 "비트 풀"을 형성합니다. DECIMAL은 숫자를 2의 보수 정수로 정확하게 나타 내기 위해 사용합니다. 소수점은 저장되지 않으며 암시됩니다.
즉, "숫자"를 CPU가 숫자로 인식하는 것으로 변환하기 위해 DB 엔진에서 ASCII에서 int 로의 변환이 필요하지 않습니다. 반올림이나 변환 오류가 없으며 CPU가 조작 할 수있는 실수입니다.
이러한 종류의 숫자에 대한 하드웨어 지원이 없기 때문에이 임의의 큰 정수에 대한 계산은 소프트웨어에서 수행해야하지만,이 라이브러리는 매우 오래되고 고도로 최적화되어 있으며 50 년 전에 IBM 370 Fortran 임의 정밀도 부동 소수점 데이터를 지원하도록 작성되었습니다 . 그것들은 여전히 CPU 정수 하드웨어로 수행되는 고정 크기 정수 대수 또는 FPU에서 수행되는 부동 소수점 계산보다 훨씬 느립니다.
스토리지 효율성의 관점에서, 부동 소수점은 각 부동 소수점에 첨부되므로 소수점이있는 위치를 암시 적으로 지정하므로 대량으로 중복되므로 DB 작업에 비효율적입니다. DB에서 소수점이 어디로 올라갈 지 이미 알고 있으며 DECIMAL 열에 대한 값을 가진 테이블의 모든 행은 소수점을 배치하고 저장하는 위치의 1 & 유일한 사양 만보고하면됩니다. 스키마에서 M 및 D 값의 의미로 DECIMAL (M, D)에 대한 인수로 사용됩니다.
다양한 형식의 응용 프로그램에 어떤 형식을 사용해야하는지 여기에 나와있는 많은 설명이 정확하므로 요점을 설명하지 않겠습니다. 링크 된 MySQL 온라인 문서를 유지 관리하는 사람은 위의 내용을 이해하지 못하고 그것을 포기하려는 사람들이 점점 좌절감을 느끼기 때문에이 글을 쓰는 데 시간이 걸렸습니다. 그들이 쓰고있는 내용을 얼마나 잘 이해하지 못했는지에 대한 좋은 표시는 주제에 대한 매우 혼란스럽고 거의 이해할 수없는 표현입니다.
마지막으로, 고정밀 부동 소수점 계산이 필요한 경우 지난 20 년 동안 부동 소수점 코드가 엄청나게 발전했으며 96 비트 및 쿼드 러플 정밀 부동 소수점에 대한 하드웨어 지원이 시작되었습니다 . 그러나 저장된 값의 조작이 중요한 경우 좋은 임의 정밀도 라이브러리가 있습니다.
MySQL에만 국한된 것이 아니라 float 형식과 10 진수 형식의 차이는 분수 값을 나타내는 방식입니다. 부동 소수점 유형은 이진수로 분수를 나타내며으로 만 값을 나타낼 수 있습니다 {m*2^n | m, n Integers}
. 1/5와 같은 값은 정확하게 반올림 할 수 없습니다 (반올림 오류 없음). 십진수는 비슷하게 제한되지만 같은 숫자를 나타냅니다 {m*10^n | m, n Integers}
. 십진법은 여전히 1/3과 같은 숫자를 나타낼 수는 없지만 종종 금융과 같은 많은 공통 분야에서 특정 소수 부분은 항상 충실도 손실없이 표현 될 수있을 것으로 기대합니다. 10 진수는 $0.20
(1/5의 1/5) 와 같은 값을 나타낼 수 있으므로 이러한 상황에서 선호됩니다.
소수는 특정 소수 자릿수를 원하는 돈과 같은 고정 수량을위한 것입니다. 부동 소수점은 부동 소수점 정밀도 숫자를 저장하기위한 것입니다.
나는 이것이 유용하다는 것을 알았다.
일반적으로 부동 소수점 값은 과학 계산에는 유용하지만 재무 / 금전 값에는 사용해서는 안됩니다. 비즈니스 중심 수학의 경우 항상 10 진수를 사용하십시오.
출처 : http://code.rohitink.com/2013/06/12/mysql-integer-float-decimal-data-types-differences/
mysql> CREATE TABLE num(id int ,fl float,dc dec(5,2));
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO num VALUES(1,13.75,13.75);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO num VALUES(2,13.15,13.15);
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM num WHERE fl = 13.15;
Empty set (0.00 sec)
mysql> SELECT * FROM num WHERE dc = 13.15;
+------+-------+-------+
| id | fl | dc |
+------+-------+-------+
| 2 | 13.15 | 13.15 |
+------+-------+-------+
1 row in set (0.00 sec)
mysql> SELECT SUM(fl) ,SUM(dc) FROM num;
+--------------------+---------+
| SUM(fl) | SUM(dc) |
+--------------------+---------+
| 26.899999618530273 | 26.90 |
+--------------------+---------+
1 row in set (0.00 sec)
mysql> SELECT * FROM num WHERE ABS(fl - 13.15)<0.01;
+------+-------+-------+
| id | fl | dc |
+------+-------+-------+
| 2 | 13.15 | 13.15 |
+------+-------+-------+
1 row in set (0.00 sec)
부동 소수점 유형 (대략적인 값)-FLOAT, DOUBLE
FLOAT 및 DOUBLE 유형은 대략적인 숫자 데이터 값을 나타냅니다 . MySQL은 단 정밀도 값으로 4 바이트를 사용하고 배정 밀도 값으로 8 바이트를 사용합니다.
FLOAT의 경우, SQL 표준은 키워드 FLOAT 다음에 괄호로 묶인 비트의 정밀도 (지수 범위는 아님)의 선택적 스펙을 허용합니다. MySQL은이 선택적 정밀도 사양도 지원하지만 정밀도 값은 스토리지 크기를 결정하는 데만 사용됩니다. 0에서 23 사이의 정밀도는 4 바이트 단 정밀도 FLOAT 열을 생성합니다. 24-53의 정밀도는 8 바이트 배정도 DOUBLE 열을 생성합니다.
MySQL은 비표준 구문 인 FLOAT (M, D) 또는 REAL (M, D) 또는 DOUBLE PRECISION (M, D)을 허용합니다. 여기서 "(M, D)"는 총 M 자리까지 값을 저장할 수있는 것보다 D 자리가 소수점 뒤에 올 수 있음을 의미합니다. 예를 들어 FLOAT (7,4)로 정의 된 열은 표시 될 때 -999.9999와 같습니다. MySQL은 값을 저장할 때 반올림을 수행하므로 FLOAT (7,4) 열에 999.00009를 삽입하면 근사 결과는 999.0001입니다.
부동 소수점 값은 근사값이며 정확한 값으로 저장되지 않으므로 값을 정확하게 비교하려고하면 문제가 발생할 수 있습니다. 또한 플랫폼 또는 구현 종속성에 종속됩니다.
이식성을 최대화하려면 대략적인 숫자 데이터 값을 저장해야하는 코드는 정밀도 나 자릿수를 지정하지 않고 FLOAT 또는 DOUBLE PRECISION을 사용해야합니다.
https://dev.mysql.com/doc/refman/5.5/en/floating-point-types.html
부동 소수점 값 문제
부동 소수점 숫자는 대략적이고 정확한 값으로 저장되지 않기 때문에 때때로 혼동을 일으 킵니다 . SQL 문에 작성된 부동 소수점 값은 내부적으로 표시된 값과 같지 않을 수 있습니다. 부동 소수점 값을 비교할 때 정확하게 처리하려고하면 문제가 발생할 수 있습니다. 또한 플랫폼 또는 구현 종속성에 종속됩니다. FLOAT 및 DOUBLE 데이터 유형에는 이러한 문제가 있습니다. DECIMAL 열의 경우 MySQL은 소수점 이하 65 자리의 정밀도로 작업을 수행하므로 가장 일반적인 부정확성 문제를 해결합니다.
다음 예제에서는 DOUBLE을 사용하여 부동 소수점 연산을 사용하여 수행 된 계산에 부동 소수점 오류가 발생하는 방법을 보여줍니다.
mysql> CREATE TABLE t1 (i INT, d1 DOUBLE, d2 DOUBLE);
mysql> INSERT INTO t1 VALUES (1, 101.40, 21.40), (1, -80.00, 0.00),
-> (2, 0.00, 0.00), (2, -13.20, 0.00), (2, 59.60, 46.40),
-> (2, 30.40, 30.40), (3, 37.00, 7.40), (3, -29.60, 0.00),
-> (4, 60.00, 15.40), (4, -10.60, 0.00), (4, -34.00, 0.00),
-> (5, 33.00, 0.00), (5, -25.80, 0.00), (5, 0.00, 7.20),
-> (6, 0.00, 0.00), (6, -51.40, 0.00);
mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b
-> FROM t1 GROUP BY i HAVING a <> b;
+------+-------+------+
| i | a | b |
+------+-------+------+
| 1 | 21.4 | 21.4 |
| 2 | 76.8 | 76.8 |
| 3 | 7.4 | 7.4 |
| 4 | 15.4 | 15.4 |
| 5 | 7.2 | 7.2 |
| 6 | -51.4 | 0 |
+------+-------+------+
결과가 맞습니다. 처음 5 개의 레코드는 비교를 만족하지 않아야하는 것처럼 보이지만 (a와 b의 값은 다르지 않은 것으로 보이지만), 요소에 따라 숫자의 차이가 10 분의 1 정도 정도이기 때문에 그렇게 할 수 있습니다. 컴퓨터 아키텍처 또는 컴파일러 버전 또는 최적화 수준과 같은 예를 들어, 다른 CPU는 부동 소수점 숫자를 다르게 평가할 수 있습니다.
열 d1과 d2가 DOUBLE이 아닌 DECIMAL로 정의 된 경우 SELECT 쿼리 결과에는 하나의 행 (위의 마지막 행) 만 포함되었을 것입니다.
부동 소수점 숫자 비교를 수행하는 올바른 방법은 먼저 숫자 간의 차이에 대해 허용 가능한 공차를 결정한 다음 공차 값과 비교하는 것입니다. 예를 들어 부동 소수점 숫자가 10 만 분의 1 (0.0001)의 정밀도 내에서 동일하면 동일하게 간주되어야한다는 데 동의하면 공차 값보다 큰 차이를 찾기 위해 비교를 작성해야합니다.
mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1
-> GROUP BY i HAVING ABS(a - b) > 0.0001;
+------+-------+------+
| i | a | b |
+------+-------+------+
| 6 | -51.4 | 0 |
+------+-------+------+
1 row in set (0.00 sec)
반대로 숫자가 동일한 행을 얻으려면 공차 값 내에서 차이를 찾아야합니다.
mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1
-> GROUP BY i HAVING ABS(a - b) <= 0.0001;
+------+------+------+
| i | a | b |
+------+------+------+
| 1 | 21.4 | 21.4 |
| 2 | 76.8 | 76.8 |
| 3 | 7.4 | 7.4 |
| 4 | 15.4 | 15.4 |
| 5 | 7.2 | 7.2 |
+------+------+------+
5 rows in set (0.03 sec)
부동 소수점 값은 플랫폼 또는 구현 종속성에 따라 다릅니다. 다음 명령문을 실행한다고 가정하십시오.
CREATE TABLE t1(c1 FLOAT(53,0), c2 FLOAT(53,0));
INSERT INTO t1 VALUES('1e+52','-1e+52');
SELECT * FROM t1;
일부 플랫폼에서 SELECT 문은 inf 및 -inf를 리턴합니다. 다른 경우에는 0과 -0을 반환합니다.
이전 문제의 의미는 마스터에서 mysqldump를 사용하여 테이블 내용을 덤프하고 덤프 파일을 슬레이브로 다시로드하여 복제 슬레이브를 만들려고하면 부동 소수점 열을 포함하는 테이블이 두 호스트간에 다를 수 있다는 것입니다.
https://dev.mysql.com/doc/refman/5.5/en/problems-with-float.html
엄격한 규칙
저장하는 숫자를 더하거나 빼거나 곱하기 만하면 DECIMAL이 가장 좋습니다.
데이터에 대해 다른 형태의 산술 또는 대수를 나누거나 수행 해야하는 경우 거의 확실하게 float로 더 행복해질 것입니다. 부동 소수점 라이브러리와 Intel 프로세서의 부동 소수점 프로세서 자체에는 일반적인 수학 함수, 특히 초월 함수를 수행 할 때 발생하는 예외를 수정, 수정, 감지 및 처리하기위한 많은 작업이 있습니다.
정확성에 관해서는 한 달에 3,600 개의 예산 단위에 대해 3,000 개 이상의 계정, 각 단위의 통합 노드에 대한 기여 비율을 계산 한 다음 예산 매트릭스 (3,000 + x 12 x 3,600)를 기반으로 예산 시스템을 작성했습니다. 가장 높은 조직 노드에 의해 예산이 책정 된 금액을 조직 노드의 다음 3 개 수준으로 곱한 다음 3,200 개의 세부 단위에 대한 모든 (3,000 + 12) 값을 계산했습니다. 수백만 및 수백만 및 수백만 배의 배정도 부동 소수점 계산 중 하나는 조직에서 가장 높은 수준으로 상향식 통합으로 모든 프로젝션의 롤업을 중단합니다.
모든 계산 후의 총 부동 소수점 오류는 ZERO 입니다. 그것은 1986 년이었고 오늘날 부동 소수점 라이브러리는 그 당시보다 훨씬 뛰어납니다. 인텔은 80 비트 정밀도로 중간 값을 두 배로 계산하여 반올림 오류를 제거합니다. 누군가가 "부동 소수점 오류"라고 말하면 거의 확실하지 않습니다.
FLOAT(m,n)
두 개의 반올림이 발생합니다. 한편, 그것은 아무것도 사용하지 않습니다.