webForumDet fria alternativet

En liten nöt för er att knäcka...

Programmering

10 svar · 449 visningar · startad av WiNNe

Medlem sedan maj 2000192 inlägg
Frågan#1

Jag ville kolla om ett tal gick jämnt upp i 1 så jag funderade lite på hur man skulle kunna göra det. Den första lösningen blev en enkel loop som adderar talet på sig själv tills det blivit 1 eller större. Om det blev 1 precis så visste jag att det gick jämnt upp.

Här är den första versionen.
-----------------------------------
function Tform1.ValidDivider ( value : extended ) : boolean;
var temp : extended;
begin
temp:=0;
while temp<1 do
temp:=temp+value;
if (temp = 1) then Result := True
else result := False;
end;

procedure TForm1.FormActivate(Sender: TObject);
begin
if validdivider ( 0.25 ) then showmessage('YEAH')
else Showmessage('NONO');
end;

----------------------------------
Problemet är att det funkar inte. Delphi vägrar göra jämförenseln (if temp=1) korrekt. Vid en första koll tror man att det är nåt skummt med nåt likhetstecken eller nån felaktig datatyp men icke.

Kom på en bättre lösning sen, där man dividerar 1 med talet och kollar om resultatet är ett heltal.

Såhär:
-----------------------
function Tform1.ValidDivider ( value : extended ) : boolean;
var temp : extended;
begin
temp:=1/value;
if frac(temp)=0 then
Result := True
else result := False;
end;

-----------------------
Nu är ju problemet löst tycker man, MEN jag skulle gärna vilja veta varför mitt första sätt inte fungerar. Har frågat på proffsajter som Experts-Exchange, men inte fått nåt vettigt svar så nu ger jag chansen till er.

------------------
winne.net

Medlem sedan aug. 20002 975 inlägg
#2

För min del gick bägge versionerna. Testade runt med olika tal i version 1 och det gick bra på alla tal jag provade som var större än 0.10.
Vi har ett program på jobbet som under utveckling gjorde något liknande fel.
Man hade lagrat in 11,2 (eller något annat) i en databas. Sedan fanns en kod som gjorde jämförelsen Om x=11,2 gör.... . Detta fungerade inte och man kom fram till att processorn lagrade värdet som 11,19999999 osv. Istället fick man skriva koden Om 11,1<x<11,3 gör... .
Det hela hade att göra med att datorn inte arbetar med exakta decimaltal. Efter någon decimal beroende på formatet blir siffrorna mer eller mindre slumpartade. (som jag fick det förklarat för mig).

Medlem sedan juni 2000350 inlägg
#3

Problemet beror inte på delphi utan på hur datorn funkar. Den måste avrunda när den jobbar med decimaltal eftersom en decimaltyp har en viss storlek men decimal tal kan inhålla oändligt många siffror. Och även om tex 4 är ett heltal så tror jag datorn lagrar/ser det som tex 3.9999999999999999999996541 när du använder extended.

Har läst en förklaring i någon gammal delphi tidning och hittar jag den så återkommer jag. Du får ta detta med en nypa salt tills jag läst på ;).

Men en sak är jag säker på man kan inte göra "exakta" jämnförelser mellan "real types" undantaget är nog Currency. Använder man Currency i din funktion så funkar den. Kollar du i hälpen för Currency så står det ochså något om att den lagras som en 64-bit integer.

Medlem sedan maj 2000192 inlägg
#4

Har fått klart för mig att det är precis som ni säger. Flyttal blir lite skumma i processorn men det som förvillar en är att delphi avrundar värdet åt en när man debuggar. Den kan säga att värdet är 1.0 fastän inne i datorn är det 0.9999999999999999.

Att använda currency är ingen lösning, har inte fått det att funka. Programmet hänger sig då.

------------------
winne.net

Medlem sedan juni 2000350 inlägg
#5

Det funkar bra med Currency för mig i D3. Testade ditt första exempel och verkade få de resultat man förväntar sig.

Medlem sedan maj 2000192 inlägg
#6

Currency funkar inte i D5. Mitt första exempel fungerar inte i Delphi 4 eller 5. Vissa tal fungerar 0.2 fungerar men inte 0.1 och inte 0.01. 0.25 fungerar inte heller.

------------------
winne.net

Medlem sedan juni 2000350 inlägg
#7

Jag menade att ditt första exempel med Currency funkade som man förväntar sig.
Med extended så fick jag samma resultat som du.

Testade att köra exempel 1 med Currency i D5 och det funkade bra.

Jag hittade artikeln jag skrev om men har bara skummat igenom den och är inte säker på att jag kan beskriva varför/hur det blir som det blir utan att cittera flera sidor ;).

Om du laddar ner 1999 Issue 51, Nov (643Kb) så hittar du en katalog med namnet Alfresco och där finns lite kod som medföljer artikeln. Projektet CvtSingle.dpr är nog det som är mest intressant, skriver ut single värden som strängar så man ser att 1/5 inte är 0,2 utan 0,20000000321. http://www.thedelphimagazine.com/dmdisk.htm

Medlem sedan maj 2000192 inlägg
#8

Ok, men länken fungerar inte.

------------------
winne.net

Medlem sedan juni 2000350 inlägg
#9

Funkar hos mig

Funkar kanske bättre med länk direkt till zip. http://www.thedelphimagazine.com/disks/dmag51.zip

Medlem sedan maj 2000192 inlägg
#10

Klart intressant liten rutin det där, synd bara att man inte är nåt matte-geni... :)

------------------
winne.net

Medlem sedan juni 2000350 inlägg
#11

Är inte heller något matte-geni.

Vilket var ett av skälen till att jag inte var så sugen på att försöka förklara artikeln ;).

258 ms totalt · 4 externa anrop · v20260731065814-full.6fe65c25
121 ms — deklarationer (db)
0 ms — hämta statistik (cache)
127 ms — hämta tråd, inlägg och bilagor (db)
128 ms — ändringar (db)