Articles

Farene ved Å bruke Float eller Ekte Datatyper

Det er en gammel vits om flytende punkt aritmetikk:

«hvis jeg kutter en kake i tre, er hvert stykke 0,33 av kaken. Hvis jeg holder alle tre stykkene sammen igjen, gir det meg 0,99 av kaken. Hvor er resten av kaken blitt av?»
— » Enkel. Det er litt fast på kniven»

Flytende punkt aritmetikk handler om å tolerere og administrere tilnærming for å unngå overløpsfeil i beregninger. I den virkelige verden bryr vi oss vanligvis om presisjon i antall og vil i stedet ofre plass og ressurser for å unngå overløp.

mens vitenskapen fungerer lykkelig innenfor en feilmargin, presisjon saker i virksomheten regnskap. Da jeg var en cub programmerer, skrev jeg en gang hva jeg trodde å være en perfekt egnet måte å beregne fortjenesten på aksjemegleravtaler. I en million pund var det en krone eller to ut på det meste. Jeg var fornøyd. Det brukte beregningene som ligger i pl / 1-kompilatoren som vi brukte på den tiden for å utvikle økonomiske pakker. Jeg viste dem den fint utformede applikasjonen, og de var forferdet. En krone ut i en million pund syntes de hardkokte byhandlerne å være hensynsløs. De ville ikke ha det. Jeg ble tvunget til å skrive en binærkodet desimal (BCD) pakke i assembler-kode som var nøyaktig nøyaktig.

SQL Prompt har en kodeanalyseregel (BP023) som vil varsle deg om bruken av FLOAT eller REAL datatyper, på grunn av de betydelige unøyaktighetene de kan introdusere for de slags beregninger som mange organisasjoner rutinemessig vil utføre på SINE SQL Server-data.

datatyper For Omtrentlig tall

flyttallsaritmetikk ble utviklet på et tidspunkt da Det var en prioritet å lagre minne samtidig som det ga en allsidig måte å gjøre beregninger som involverte store tall. Selv om det er fortsatt nyttig for mange typer vitenskapelige beregninger, spesielt de som er i samsvar med dobbel presisjon ieee 754 standard for flyttall aritmetikk, det er, av nødvendighet, et kompromiss. Ledetråden er i navnet på denne typen data og aritmetikk: ‘omtrentlig’. Flyttall kan ikke nøyaktig representere alle reelle tall: dess, flyttallsoperasjoner kan ikke nøyaktig representere alle aritmetiske operasjoner. Imidlertid er størrelsesområdet for tallet de kan holde langt større enn det som er mulig i andre numeriske typer, selv om det ikke alltid holdes nøyaktig.

problemene som oppstår ved bruk av flyttallsberegninger skyldes avrunding under komplekse beregninger, og er oftest sett hvis dataene er ‘dårlig betinget’, slik at små endringer i input forstørres i output. Unøyaktigheter er langt mindre tydelig med økt presisjon av representasjon av tallene, men de er fortsatt til stede, likevel. Det er også noen esoteriske begrensninger i bruken av tall som er gyldige, men ikke kan representeres i flytende punkt, for eksempel tan(π / 2), men disse vil sannsynligvis bare opphisse matematikere.

flytende punktdatatyper FOR SQL Server

SQL-Standarden har tre flytende punkt, omtrentlige datatyper,REALDOUBLEPRECISION ogFLOAT(n). SQL Server samsvarer med dette, bortsett fra at den ikke har noen DOUBLEPRECISION datatype, ved hjelp av FLOAT(53) i stedet. FLOAT(24) ogFLOAT(53) datatypene tilsvarer Binary32 (Enkelt) Og Binary64 (dobbelt) i IEEE 754-standarden, og lagres i 4 og 8 byte, og 7 og 16 sifre holdes tilsvarende. De er nyttige når det er viktig at beregninger gir samme resultat som et program som bruker. NET framework som også bruker ieee 754. Den doble presisjonstypen er også nødvendig når tallene overstiger i sin størrelse maksimalt tillatt av DECIMAL datatypen (38 sifre), men med tap i presisjon. Omtrentlige tall kan selvfølgelig ikke brukes pålitelig i noen likhetstest, for eksempel en WHERE – klausul.

Beregninger ved HJELP AV DEN VIRKELIGE datatypen (single precision)

jeg vil prøve REAL datatypen. FLOAT(24) datatypen, eller mindre, reagerer på samme måte. Det første du må huske når du eksperimenterer med flyttall i SQL Server er AT SSMS gjengir et flyttall på en måte som skjuler små forskjeller. For eksempel:

Velg Konverter(EKTE,0.100000001490116119384765625)

1

…gir 0.1

for å se mer nøyaktig hvilken verdi som er lagret i et flyttall, må du bruke str () – funksjonen, og angi Presisjonen DU FAKTISK vil ha.

/*jeg er litt urettferdig her, fordi desimaltallet 0.1 ikke er representabelt
i flytende punkt; den nøyaktige binære representasjonen vil ha en «1100» sekvens
fortsetter uendelig:*/
erklære @firstapproximate real = 0.1
velg str(@firstapproximate,20,16)-skal være 0.100000001490116119384765625
1
2
3
5

Dette er alarmerende. Vi er, tross alt, arbeider med data med millioner av rader så små feil vil stable opp med mindre, som ‘bankfolk avrunding’, de gjennomsnitt ut. Den feilen er allerede nær ‘ penny i en million pund ‘(1 / 240000000) som jeg nevnte i introduksjonen!

La oss unngå 0.1 og sette det ned til et flytende punkt. Hva med å dele 1 av 3? Sikkert dette kan ikke være et problem?

angir @divisor real = 3
velg str (@utbetalinger /@divisor,20,16) som kvotient
–produserer 0.33333333432674408
–bør være 0.33333333333333

1
2
4
5

oops. Det tok feil. OK, DET er en liten feil, men husk min historie om bankfolk. Et svar er enten riktig eller det er galt, det er ingen nyanser av grått for menn i grå dresser. I handelshøyskolen er det bare et kryss og et kryss. Ingen tegn som betyr ‘nær nok’.

en enkel test er å dele en med tall fra en til tjue. Hva kan gå galt?

vi kan lagre resultatene av flyttall og numerisk beregning, både konvertert til strenger og vi deretter sammenligne strengene(vær advart om at STR() kan sette i en ledende plass som gjør for en komplikasjon).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

DECLARE @divisor REAL, @dividend REAL = 1
DECLARE @FloatingPointCalculations TABLE (Divisor INT, QuotientFloatingPoint VARCHAR(20), QuotientNumeric VARCHAR(20));
DECLARE @ii INT = 1;
DECLARE @iiMax INT = 20;
WHILE (@ii <= @iiMax)
BEGIN
SELECT @divisor = @ii;
INSERT INTO @FloatingPointCalculations (Divisor, QuotientFloatingPoint,
QuotientNumeric)
SELECT @ii AS divisor, Str(@Dividend / @divisor, 20, 16) AS QuotientFloatingPoint,
Convert(VARCHAR(20), 1.0000000 / @ii) AS QuotientNumeric;
SELECT @ii += 1;
END;
SELECT The.Divisor, The.QuotientFloatingPoint, The.QuotientNumeric
FROM @FloatingPointCalculations AS The;

Now, what if we list the rows where the numbers don’t match?

1
2
3

SELECT The.Divisor, The.QuotientFloatingPoint, The.QuotientNumeric
FROM @FloatingPointCalculations The
WHERE Left(LTrim(The.QuotientFloatingPoint),16)<> Left(LTrim(The.16)

Ugh! Bare hvor divisoren var 1, 2, 4, 8 eller 16 var det et riktig resultat.

hvis du håper at flottøren på en eller annen måte var nøyaktig, og den numeriske versjonen ikke var, er den numeriske kvotienten beregnet i Excel:

Beregninger ved HJELP AV FLOAT(25) eller over (dobbel presisjon)

hvis du bruker dobbel presisjon flyttall, FLOAT(25) eller over, testene er alle bestått, på grunn av STR() funksjonen tillater maksimalt seksten plasser til høyre for desimaltegnet. Hvis det er mer enn 16, blir resultatet avkortet. Datatypen med dobbel presisjon har seksten sifre, mens datatypen med enkel presisjon har syv. Du har også sett at single precision datatypen får de første syv sifrene riktig. På samme måte får dobbeltpresisjonen de første seksten sifrene riktig. Vi kan bare utvide tallet for å se tilnærmingen.

1

DEKLARERE @Førstapproximate FLYTE(53) = 10000000000000000.1
velg str(@firstapproximate,40,16) som bignumberwithadecimal

den brøkdelen har forsvunnet, har den ikke? Det er sannsynligvis bare en liten forskjell, men i noen beregninger kan det føre til problemer.

Konklusjon

flyttall aritmetikk er rask og økonomisk på lagring, men gir et omtrentlig resultat. Den er egnet for velkondisjonerte vitenskapelige applikasjoner, men ikke for økonomiske beregninger, noe som krever at et tall er enten ‘riktig’ eller ‘feil’. Det har også den ekstra ulempen i en database fordi du ikke kan pålidelig og konsekvent teste to omtrentlige tall for likestilling.

det er ikke riktig å si at du aldri skal bruke flyttall i SQL datatyper eller i aritmetikk. Omtrentlige typer er der I SQL-standarden for et formål. Jeg vil i dag alltid holde fast med double precision floating-point datatypen I SQL Server, der det er et passende krav. De er gode for slike formål som modellering av værsystemer eller plotting av baner, men ikke for de typer beregninger som den gjennomsnittlige organisasjonen sannsynligvis vil bruke en database for.

hvis du oppdager feilaktig bruk av disse typene, bør du bytte til en passendeDECIMALNUMERIC skriv i stedet. Hvis du vet at du trenger flytende punkt aritmetikk og kan forklare hvorfor, så vet du sikkert nok til å unngå fallgruvene til flytende punkt, for eksempel den som skjedde i den berømte Patriot-missilfeilen som førte direkte til 28 dødsfall.