C# double en sql server float

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • ? ?
  • Registratie: Mei 2007
  • Niet online
De C# double zou gelijk moeten zijn aan de SQL Server float.
Aldus MSDN: SQL Server Data Type Mappings

VS C# 2010 & SQL Server 2012

Ik wil de waarde 0.0533047 in een double stoppen.

Als ik dat via C# code doe:
double test = 0.0533047D;

Dan krijg ik 0.053304699999999997.

In C# programma code:
code:
1
2
3
double test1 = 0.0533046D; // geeft 0.0533046
double test1 = 0.0533047D; // geeft 0.053304699999999997
double test2 = 0.0533048D; // geeft 0.0533048


Als ik echter een waarde uit een SQL veld (datatype float) lees, dan krijg ik wel precies 0.0533047 in een double.
code:
1
double test4 = datareader.GetDouble(0); // geeft dan de waarde van 0.0533047 voor test4



//Ik heb een programma dat cijfers als tekst exporteert. Een 2e programma leest die tekst in en converteert naar een cijfer en dan opslaan in een database. Ik ben dat 2e programma (VBA code...) aan het vervangen, maar bij het testen komt mijn programma niet 100% overeen, met bovenstaande afwijkingen.

Ik begrijp dat een datatype niet elk getal kan storen, maar waarom kan het dat wel als ik het uit SQL haal??

Acties:
  • 0 Henk 'm!

  • Daos
  • Registratie: Oktober 2004
  • Niet online
Geen idee waarom je verschil krijgt, maar wat je moet weten is dat float/doubles voor wetenschappelijke waardes is bedoeld (google maar eens wetenschappelijke notatie en significante cijfers).

Wil je een vast aantal decimalen (bv om geld op te slaan), dan moet je het datatype decimal (zowel in C# als SQL) gebruiken.

Acties:
  • 0 Henk 'm!

  • Haan
  • Registratie: Februari 2004
  • Laatst online: 20:14

Haan

dotnetter

Inderdaad beter decimals gebruiken, tenzij performance echt heel kritisch is, rekenen met doubles/floats is namelijk sneller dan rekenen met decimals, maar daar zul je in normale situaties niet snel iets van merken.

Kater? Eerst water, de rest komt later


Acties:
  • 0 Henk 'm!

  • ? ?
  • Registratie: Mei 2007
  • Niet online
Het gaat o.a. over xyleen waarden in de lucht. Het is niet mijn keuze om dit datatype te kiezen en in de rapportering (=grafiek) doet het er eigenlijk weinig ter zake of het 3/4/5/6e cijfer klopt.
Tevens is het veld in de database een float en dat mag/moet niet gewijzigd worden.

Om te controleren of het nieuwe programma dezelfde gegevens invoert (adhv de reeds bestaande waarden), heb ik nu een 0,1 marge ingebouwd om de echte verschillen (lees fouten) er uit te halen.

Alleen zou ik eens het waarom van bovenstaande willen weten.

[ Voor 8% gewijzigd door ? ? op 02-07-2015 16:34 ]


Acties:
  • 0 Henk 'm!

  • Daos
  • Registratie: Oktober 2004
  • Niet online
Als ik 0.0533047D op de console print zonder toevoegingen, krijg ik gewoon 0.0533047 (VS 2010 Express).
C#:
1
2
double test2 = 0.0533047D; 
Console.WriteLine("{0}", test2); // geeft 0.0533047


In jouw geval gaat het om een wetenschappelijke waarde en is dus een float/double de juiste keuze. Je moet alleen even bedenken hoeveel significante cijfers je weer wilt geven en bij het uitvoeren het aantal decimalen beperken. Zie MSDN: Custom Numeric Format Strings Bv zoiets:
C#:
1
Console.WriteLine("{0:0.000000}", test2); // geeft 0.053305

Acties:
  • 0 Henk 'm!

  • Feanathiel
  • Registratie: Juni 2007
  • Niet online

Feanathiel

Cup<Coffee>

Hoewel ik het met de rest eens ben, even een korte uitleg. (Kort is toch wat langer geworden zie ik net. ;( )

Als je C# code compileert, de constanten daarvan worden hard vast gezet in MSIL. Zo is je eerste waarde (0.0533046D) bijvoorbeeld opgeslagen als 'ldc.r8 5.3304600000000001e-002'. Dit wordt compiletime bepaald. Runtime is het echter een ander verhaal. Er zit gewoon andere code tussen die de expressies uitvoert, en zal op een ander resultaat terecht komen. Dit kan zelfs per machine verschillen.

Probeer maar eens:
C#:
1
2
static double Get(double d) { return d; }
double e = Get(0.533047D)/10d; 

in debug-modus uit te voeren. Je zult zien dat je een ander resultaat krijgt dan vast 0.0533046D erin te zetten. Zelfs 0.533046D / 10 geeft je hetzelfde als het eerste resultaat, omdat de compiler kan zien dat de waarde tussendoor niet veranderd. Deze waarde wordt dan hard in de assembly (MSIL) gezet.

Even een uitstapje. In .NET kun je ook geheugen uitlezen als andere datatypen, ookal heb je dat onder een ander datatype opgeslagen. Zo kun je bijvoorbeeld:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
[StructLayout(LayoutKind.Explicit)]
internal struct Storage
{
    [FieldOffset(0)]
    public Int64 _long;
    [FieldOffset(0)]
    public double _double;
}

Storage storage = new Storage();
storage._double = 0.533047D;
// storage._long; ?


Gebruiken om te zien welke bits er zijn gezet bij specifieke getallen. Je zult dan zien dat er verschillende getallen worden (bits) gebruikt worden om verschillende representaties voor elkaar te krijgen.

4587842823490102699 - 0.0533046
4602976480086418338 - 0.053304699999999997
4587842837901621507 - 0.0533047
4587842852313140314 - 0.0533048


Mantissa en exponent kun je vervolgens zelf wel bepalen denk ik.

Het SQL-framework stuurt ruwe bits/bytes over de lijn. Deze worden later omgezet zodat de representatie wel mogelijk is. De struct Storage komt dan ook van http://referencesource.mi...ver/SqlRecordBuffer.cs,40

Lang verhaal kort; gebruik gewoon Decimal (base10) als decimalen echt uitmaken. :)

@hieronder:

Lijkt mij juist wel relevant omdat de vraag gesteld wordt:
"Ik begrijp dat een datatype niet elk getal kan storen, maar waarom kan het dat wel als ik het uit SQL haal??"

[ Voor 13% gewijzigd door Feanathiel op 03-07-2015 15:49 ]


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Of je leest de Getallen en talstelsels FAQ even. Heel MSIL en whatnot is totaal niet relevant in dit verhaal en heel bovenstaande uitleg maakt 't allemaal nodeloos ingewikkeld.

[ Voor 15% gewijzigd door RobIII op 02-07-2015 21:42 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij

Pagina: 1