Yanıtlar:
Bu şüphem olduğunda bulduğum şey bu.
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
Ondalık, bu durumlarda ne yapılması gerektiğini tam olarak yaptı, gerisini kısalttı ve böylece 1/3 bölümünü kaybetti.
Yani toplamlar için ondalık daha iyidir, ancak bölümler için kayan nokta elbette bir noktaya kadar daha iyidir. Demek istediğim, DECIMAL kullanmak hiçbir şekilde "başarısızlığa dayanıklı aritmetik" vermeyecektir.
Bu yardımcı olur umarım.
@a
99.999999999000000000000000000000'e DECIMAL verilmiyor mu? Hangi teknik olarak doğru.
Çoğu ortamda bir "kayan nokta" ikili kayan nokta türüdür. Base-2 değerlerini (belirli bir noktaya) doğru bir şekilde depolayabilir, ancak birçok base-10 (ondalık) değerini doğru bir şekilde depolayamaz. Şamandıralar bilimsel hesaplamalar için en uygun olanlardır. Onlar konum değil en iş odaklı matematik için mülk ve yüzen uygunsuz kullanımı seni ısıracak. Birçok ondalık değer temel-2'de tam olarak temsil edilemez. 0.1
mesela tutamazsınız ve böylece garip sonuçlar görürsünüz 1.0 - 0.1 = 0.8999999
.
Ondalıklar temel-10 sayılarını saklar. Ondalık, çoğu işletme matematiği için iyi bir türdür (ancak herhangi bir yerleşik "para" türü finansal hesaplamalar için daha uygundur); değer aralığının tamsayı türlerinin sağladığı ve kesirli değerlerin gerekli olduğu değerlerden fazladır. Ondalık sayılar, adından da anlaşılacağı gibi, taban-10 sayılar için tasarlanmıştır - ondalık değerleri doğru bir şekilde saklayabilirler (yine belirli bir noktaya).
MySQL yakın zamanda DECIMAL tipini saklama şekillerini değiştirdi . Geçmişte, her bir basamak için, bir sayının - bir - ikisinin tamamlayıcı tamsayısının veya bir türevinin bir ASCII (veya nybble) gösterimini içeren karakterleri (veya nybble'ları) sakladılar.
DECIMAL için geçerli depolama biçimi, bitleri, sizin tarafınızdan tanımlanan zımni ondalık nokta ile ikisinin tamamlayıcı numarasını oluşturmak üzere birleştirilen ve beyan ettiğinizde DB şemasında saklanan 1,2,3 veya 4 baytlık tamsayılardan oluşan bir seridir sütun ve DECIMAL boyutu ve ondalık nokta konumunu belirtin.
Örnek olarak, bir 32 bit int alırsanız 0 - 4,294,967,295 arasında herhangi bir sayı saklayabilirsiniz. Bu sadece 999,999,999'u güvenilir bir şekilde kapsayacaktır, bu yüzden 2 bit atıp (1 << 30 -1) kullandıysanız hiçbir şeyden vazgeçmezsiniz. 9 basamaklı sayıların tümünü yalnızca 4 baytla örtmek, 4 ASCII karakteri veya 8 nybble basamağı kullanarak 32 bitlik 4 basamağı örtmekten daha etkilidir. (bir nybble 4 bittir, 0-15 değerlerine izin verir, 0-9 için gerekli olandan daha fazladır, ancak 3 bit'e giderek bu atığı ortadan kaldıramazsınız, çünkü bu sadece 0-7 değerlerini kapsar)
MySQL çevrimiçi dokümanlarında kullanılan örnekte örnek olarak DECIMAL (18,9) kullanılmıştır. Bu, yukarıda açıklandığı gibi aşağıdaki depolamayı gerektiren zımni ondalık noktasının 9 basamak önünde ve 9 basamaktır.
18 8 bit karakter olarak: 144 bit
18 4 bitlik sallanma olarak: 72 bit
2 32 bit tam sayı olarak: 64 bit
Şu anda DECIMAL, izin verilen M için en büyük değerin 65 ve izin verilen en büyük D değerinin 30 olduğu DECIMAL (M, D) olarak maksimum 65 haneyi desteklemektedir.
Bir seferde 9 basamaklı parçalar gerektirmeyecek şekilde, 1,2 bit'ten küçük tamsayılar 1,2 ve 3 bayt tamsayıları kullanarak basamak eklemek için kullanılır. Herhangi bir nedenden ötürü mantığa meydan okuyan, imzasız imzalar yerine imzalı imzalar kullanıldı ve bu şekilde 1 bit atılarak aşağıdaki depolama yetenekleri ortaya çıktı. 1,2 ve 4 baytlık atlar için kayıp bitin önemi yoktur, ancak 3 baytlık int için bu bir felakettir, çünkü tek bir bitin kaybı nedeniyle tüm bir basamak kaybedilir.
7 bit int ile: 0 - 99
15 bit int ile: 0 - 9.999
23 bit int ile: 0 - 999,999 (24 bit int ile 0 - 9,999,999)
1, 2, 3 ve 4 bayt tamsayıları birleştirilerek DECIMAL, sayıyı tam olarak ikinin tamamlayıcı tamsayısı olarak göstermek için bir "bit havuzu" oluşturur. Ondalık nokta saklanmaz, ima edilir.
Bu, "sayıyı" CPU'nun sayı olarak tanıdığı bir şeye dönüştürmek için DB motorunun ASCII'den int'ye dönüşüm gerektirmediği anlamına gelir. Yuvarlama yok, dönüştürme hatası yok, CPU'nun manipüle edebileceği gerçek bir sayı.
Bu tür bir sayı için donanım desteği olmadığından, bu keyfi büyük tamsayıya ilişkin hesaplamalar yazılımda yapılmalıdır, ancak bu kütüphaneler çok eski ve son derece optimize edilmiştir, 50 yıl önce IBM 370 Fortran keyfi hassas kayan nokta verilerini desteklemek için yazılmıştır. . CPU tamsayı donanımı ile yapılan sabit boyutlu tamsayı cebirinden veya FPU'da yapılan kayan nokta hesaplamalarından hala çok daha yavaştırlar.
Depolama verimliliği açısından, bir şamandıranın üssü, her şamandıraya bağlı olduğundan, ondalık noktanın nerede olduğunu dolaylı olarak belirterek, büyük ölçüde gereksizdir ve bu nedenle DB çalışması için verimsizdir. Bir DB'de, ondalık noktanın nereye kadar çıkacağını zaten biliyorsunuz ve tablodaki DECIMAL sütunu için bir değere sahip olan her satırın, yalnızca ondalık noktanın nereye yerleştirileceği, saklanacağı 1 ve yalnızca spesifikasyonuna bakması gerekiyor şemada M ve D değerlerinin iması olarak DECIMAL (M, D) argümanları olarak.
Burada, çeşitli uygulamalar için hangi formatın kullanılacağına dair birçok açıklama doğrudur, bu yüzden konuyu işaretlemeyeceğim. Buraya yazmak için zaman ayırdım çünkü kim bağlı MySQL çevrimiçi dokümantasyonunu koruyorsa, yukarıdakilerden hiçbirini anlamaz ve gittikçe artan sinir bozucu girişimlerin ardından anladım. Ne yazdıklarını ne kadar iyi anlamadıklarının iyi bir göstergesi, konunun çok karışık ve neredeyse anlaşılmaz bir sunumudur.
Son bir düşünce olarak, yüksek hassasiyetli kayan nokta hesaplamasına ihtiyacınız varsa, son 20 yılda kayan nokta kodunda muazzam gelişmeler oldu ve 96 bit ve Dörtlü Hassas şamandıra için donanım desteği hemen köşede, ancak depolanan değerin manipülasyonu önemliyse iyi keyfi hassas kütüphaneler vardır.
Sadece MySQL'e özgü değil, float ve ondalık tipler arasındaki fark, bunların kesirli değerleri temsil etme şeklidir. Kayan nokta türleri, ikili olarak yalnızca değerleri temsil edebilen kesirleri temsil eder {m*2^n | m, n Integers}
. 1/5 gibi değerler tam olarak temsil edilemez (yuvarlama hatası olmadan). Ondalık sayılar benzer şekilde sınırlıdır, ancak benzer sayıları temsil eder {m*10^n | m, n Integers}
. Ondalık sayılar hala 1/3 gibi sayıları temsil edemez, ancak genellikle finans gibi birçok ortak alanda, belirli ondalık kesirlerin her zaman sadakat kaybı olmadan ifade edilebileceği beklentisi söz konusudur. Ondalık bir sayı $0.20
(bir doların beşte biri) gibi bir değeri temsil edebileceğinden , bu durumlarda tercih edilir.
ondalık, belirli sayıda ondalık basamak olmasını istediğiniz sabit para miktarı içindir. Şamandıralar kayan nokta hassas sayılarını saklamak içindir.
Bu yararlı buldum:
Genellikle, Float değerleri bilimsel Hesaplamalar için iyidir, ancak Finansal / Parasal Değerler için kullanılmamalıdır. İş Odaklı Matematik için her zaman Ondalık değerini kullanın.
Kaynak: 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)
Kayan Nokta Tipleri (Yaklaşık Değer) - FLOAT, DOUBLE
FLOAT ve DOUBLE tipleri yaklaşık sayısal veri değerlerini temsil eder . MySQL, tek duyarlıklı değerler için dört bayt ve çift duyarlıklı değerler için sekiz bayt kullanır.
FLOAT için SQL standardı, parantez içindeki FLOAT anahtar sözcüğünü izleyen bitlerde kesinlikteki isteğe bağlı (ancak üs aralığının değil) spesifikasyonuna izin verir. MySQL de bu isteğe bağlı hassasiyet özelliğini destekler, ancak hassasiyet değeri yalnızca depolama boyutunu belirlemek için kullanılır. 0 ile 23 arasında bir kesinlik, 4 baytlık tek kesinlikli FLOAT sütununa neden olur. 24'ten 53'e kadar bir hassasiyet, 8 baytlık çift hassasiyetli ÇİFT sütununa neden olur.
MySQL, standart olmayan bir sözdizimine izin verir: FLOAT (M, D) veya REAL (M, D) veya ÇİFT HASSASİYET (M, D). Burada, “(M, D)”, değerlerin toplamda en fazla M hane ile saklanabileceği anlamına gelir; bunların D haneleri ondalık noktadan sonra olabilir. Örneğin, FLOAT (7,4) olarak tanımlanan bir sütun görüntülendiğinde -999.9999 şeklinde görünecektir. MySQL değerleri depolarken yuvarlama yapar, bu nedenle bir FLOAT (7,4) sütununa 999.00009 eklerseniz yaklaşık sonuç 999.0001 olur.
Kayan nokta değerleri yaklaşık olduğundan ve kesin değerler olarak saklanmadığından, karşılaştırmalarda kesin olarak ele alma girişimleri sorunlara yol açabilir. Ayrıca platform veya uygulama bağımlılıklarına da tabidirler.
Maksimum taşınabilirlik için, yaklaşık sayısal veri değerlerinin saklanmasını gerektiren kod, doğruluk veya basamak sayısı belirtmeksizin FLOAT veya ÇİFT HASSASİYET kullanmalıdır.
https://dev.mysql.com/doc/refman/5.5/en/floating-point-types.html
Kayan Nokta Değerleriyle İlgili Sorunlar
Kayan noktalı sayılar bazen karışıklığa neden olur, çünkü bunlar yaklaşıktır ve kesin değerler olarak saklanmazlar . SQL ifadesinde yazılan kayan nokta değeri, dahili olarak temsil edilen değerle aynı olmayabilir. Kayan nokta değerlerini karşılaştırmalarda kesin olarak ele alma girişimleri sorunlara yol açabilir. Ayrıca platform veya uygulama bağımlılıklarına da tabidirler. FLOAT ve DOUBLE veri türleri bu sorunlara tabidir. DECIMAL sütunları için MySQL, en sık görülen yanlışlık sorunlarını çözmesi gereken 65 ondalık basamak hassasiyetiyle işlemler gerçekleştirir.
Aşağıdaki örnek, kayan nokta işlemleri kullanılarak yapılan hesaplamaların kayan nokta hatasına nasıl tabi olduğunu göstermek için DOUBLE işlevini kullanır.
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 |
+------+-------+------+
Sonuç doğrudur. İlk beş kayıt karşılaştırmayı tatmin etmemeleri gibi görünse de (a ve b değerleri farklı görünmüyor), bunu yapabilirler, çünkü sayılar arasındaki fark, faktörlere bağlı olarak onuncu ondalık civarında görünür örneğin bilgisayar mimarisi veya derleyici sürümü veya optimizasyon düzeyi. Örneğin, farklı CPU'lar kayan nokta sayılarını farklı değerlendirebilir.
D1 ve d2 sütunları DOUBLE yerine DECIMAL olarak tanımlanmış olsaydı, SELECT sorgusunun sonucu yalnızca bir satır (yukarıda gösterilen son satır) içerecekti.
Kayan noktalı sayı karşılaştırması yapmanın doğru yolu, önce sayılar arasındaki farklar için kabul edilebilir bir toleransa karar vermek ve ardından tolerans değeri ile karşılaştırmayı yapmaktır. Örneğin, kayan nokta sayılarının on binde (0.0001) bir doğrulukta aynıysa aynı kabul edilmesi gerektiğini kabul edersek, tolerans değerinden daha büyük farklılıklar bulmak için karşılaştırma yazılmalıdır:
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)
Tersine, sayıların aynı olduğu satırları almak için test tolerans değeri içinde farklılıklar bulmalıdır:
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)
Kayan nokta değerleri, platform veya uygulama bağımlılıklarına tabidir. Aşağıdaki ifadeleri yürüttüğünüzü varsayalım:
CREATE TABLE t1(c1 FLOAT(53,0), c2 FLOAT(53,0));
INSERT INTO t1 VALUES('1e+52','-1e+52');
SELECT * FROM t1;
Bazı platformlarda SELECT deyimi inf ve -inf değerlerini döndürür. Diğerlerinde 0 ve -0 döndürür.
Önceki sorunların bir sonucu olarak, master'a mysqldump ile tablo içeriğini dökerek ve döküm dosyasını slave'e yeniden yükleyerek çoğaltma slave'i oluşturmaya çalışırsanız, kayan nokta sütunları içeren tablolar iki ana bilgisayar arasında farklılık gösterebilir.
https://dev.mysql.com/doc/refman/5.5/en/problems-with-float.html
Zor ve Hızlı Kural
Yapmanız gereken tek şey sakladığınız sayıları toplamak, çıkarmak veya çarpmaksa, DECIMAL en iyisidir.
Verilere bölmeniz veya başka bir aritmetik veya cebir biçimi yapmanız gerekiyorsa, neredeyse kesinlikle şamandıra ile daha mutlu olacaksınız. Kayan nokta kütüphaneleri ve Intel işlemcilerde, kayan nokta işlemcinin kendisi, tipik matematik işlevleri, özellikle de aşkın işlevler yaparken oluşan istisnaların kar fırtınasını düzeltmek, düzeltmek, tespit etmek ve işlemek için TON işlemlerine sahiptir.
Doğruluğa gelince, bir keresinde 3.600 bütçe birimi için 3.000 bütçe biriminin her birinin% katkısını o birimin konsolidasyon düğümüne ayıran ve daha sonra bu yüzde matrisine (3.000 + x 12 x 3.600) dayanan bir bütçe sistemi yazdım. En yüksek kuruluş düğümleri tarafından bütçelenen tutarları kuruluş düğümlerinin sonraki 3 düzeyine kadar çarptım ve daha sonra tüm 3.200 ayrıntı birimi için tüm (3.000 + 12) değerleri hesapladım. Milyonlarca ve milyonlarca ve milyonlarca çift hassas kayan nokta hesaplaması, bunlardan herhangi biri dipteki bir konsolidasyondaki tüm projeksiyonların organizasyondaki en üst seviyeye çıkmasını sağlar.
Tüm bu hesaplamalardan sonraki toplam kayan nokta hatası SIFIR idi . Bu 1986'daydı ve bugün kayan nokta kütüphaneleri eskisinden çok daha iyi. Intel, yuvarlama hatasını ortadan kaldıran tüm bunların 80 bit hassasiyetinde ara hesaplamaları yapar. Birisi size "bu kayan nokta hatası" dediğinde neredeyse kesin DEĞİLDİR.
float
(ve double
) ikili kesirleri temsil eder
decimal
ondalık kesirleri temsil eder
declare @float as float(10)
declare @Decimal as decimal(10)
declare @Inetger as int
set @float =10.7
set @Decimal =10.7
set @Inetger=@Decimal
print @Inetger
değeri tamsayı baskı 10 olarak ayarlandığında floatta ancak ondalık 11'de
FLOAT(m,n)
, iki yuvarlamaya yol açar; bu arada, herhangi bir kullanım sağlar.