12. maj 2007 - 16:33Der er
13 kommentarer og 1 løsning
Afrunding RoundTo og SimpleRoundTo
Nogen der kan forklare hvorfor afrunding ikke fungerer i Delphi7 RoundTo og SimpleRoundTo Nedenstående eksempel afrunder hårdnakket 74,085 til 74.08 mens 74,085000000000001 afrunders korrekt til 74.09 Det har formodentlif noget med SetRoundMode eller Set8087CW at gøre, men ligegyldigt hvad jeg gør fejler den. Hvem kan levere den skudsikre afrundingsmetode?
et oplagt gæt vil være at 74,085 ikke kan repræsenteres eksakt i en double data type og derfor gemmes som 74,08499999999999999999 og så gør afrunding jo det den skal
Ja det er jo det der er problemet, men lidt utroligt hvis ingen har kunnet præstere den endegyldige afrundingsmetode til en Double? Og lidt mærkeligt at der eksiterer en librarymetoder der reelt ikke fungerer
Æw Et øjeblik toede jeg lige det førsate forslag virkede men nu rundes f.eks -74,084 af til -74,07, og det er jo helt i skoven. Det andet virker heller ikke - fe.ks 74,084 -> 74.09. Det kan nok ikke lade sig gøre.
Hvis din mindste værdi er "ører" registrer du ørene, fremfor et decimaltal, eksempelvis kr. 12,25. Gem det som 1255 ører. Derved får du både hurtigere sammentællinger og ingen decimaler at tumle med - hvis altså jeg har forstået arne_v korrekt.
Erve: Du skrev "lidt mærkeligt at der eksiterer en librarymetoder der reelt ikke fungerer".
Jeg har været udsat for dette fænomen ofte, og reelt drejer det dig ikke om at en library-metode ikke fungerer; problemet er at ingen datatype -uanset om vi taler Delphi, C, Basic, Python etc- kan repræsentere alle decimal-tal helt præcist.
I det konkrete tilfælde er du faldet ned i hullet fordi som arne siger din float lige præcis ikke kan repræsenteres exakt med "nuller og ettaller" som jo er byggestenen i alle taltyper.
Rent grundlæggende er problemet således hverken datatypen eller afrundingsalgoritmen, men derimod at brugeren (du selv) propper tal ind som ikke kan repræsenteres præcist. Diverse finurlige algorithmer kan ikke løse det grundlæggende problem at visse tal ikke kan repræsenteres med nuller og ettaller.
Hvis det er vigtigt for dog med 3 decimaler, så prøv evt X=(round(Val*1000.0))/1000.0
function Afrund(const Amount: Double): Double; begin Result := AfrundJB(Amount).NewMount; end;
function FindRestVedAfrundning(const tal: Currency): Currency; begin Result := AfrundJB(Tal).Diff; end;
Skal du konvetere en streng til et tal kan jeg anbefale den her :
function SVal(s: string): Double; begin s := StringReplace(s, CURRENCYstring, '', [rfReplaceAll, rfIgnoreCase]);
if DecimalSeparator = '.' then s := StringReplace(s, ',', '.', [rfReplaceAll, rfIgnoreCase]) else s := StringReplace(s, '.', ',', [rfReplaceAll, rfIgnoreCase]);
s := StringReplace(s, ' ', '', [rfReplaceAll, rfIgnoreCase]); Result := StrToFloatDef(s, 0); end;
Skal du sikre dig at der kun kan skrives noget bestemt i et exitfelt så brug den her :
type TCharSet = set of Char;
procedure ValidateEdit(Edit: TEdit; ValidChars: TCharSet = ['0'..'9', ',']); var s: string; i: Integer; begin s := Edit.Text;
for i := Length(s) downto 1 do if not (s[i] in ValidChars) then Delete(s, i, 1);
Edit.Text := s; Edit.SelStart := Length(s); end;
Og svar på din oprindelige spørgsmål : "Nogen der kan forklare hvorfor afrunding ikke fungerer i Delphi7 ... "
Så finder du svaret i delphis online hjælp :
"In Delphi, the Round function rounds a real-type value to an integer-type value.
X is a real-type expression. Round returns an Int64 value that is the value of X rounded to the nearest whole number. If X is exactly halfway between two whole numbers, the result is always the even number. This method of rounding is often called "Banker’s Rounding".
If the rounded value of X is not within the Int64 range, a runtime error is generated, which can be handled using the EInvalidOp exception.
Note: The behavior of Round can be affected by the Set8087CW procedure or SetRoundMode function."
Jeg gentager lige det vigtigste :
If X is exactly halfway between two whole numbers, the result is always the even number. This method of rounding is often called "Banker’s Rounding".
Så du må kode dine egne afrundings metoder som jeg har gjort. Hvis du bare vil afrunde til nærmeste heltal, efter de regler du har lært i skolen, gør du det vet at ligge 0,5 til og truncere resultatet.
Jeg accepterer, fordi der er kode med. Du diskuterer godt nok ikke simpleRoundTo, som ikke anvender bankers rounding, men derimod "asymmetric arithmetic rounding." Denne skulle virke. Nu har jeg selv omkodet noget javakoder, der anvender et princip om at lægge et lille´bitte tal til. Den virker ret godt, men sikkert ikke 100% heller.
"Jeg accepterer, fordi der er kode med." ... Skriver du. En passende øvelse vil således være at lukke spørgsmålet, og ikke ligge et svar selv Jens B
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.