17. marts 2011 - 20:40
Der er
6 kommentarer og
1 løsning
BCMath Arbitrary Precision Mathematics
Hej folkens,
Jeg forsøger at lave en kemisk beregning i PHP - af pH-værdien af vandige opløsninger af syrer i meget lave koncentrationer. De meget lave koncentrationer medfører, at tallene vil være meget små - tilsyneladende mindre end PHP umiddelbart kan regne med dem. Mit script ser ud som følgende:
$cs = pow(10, -8);
$ks = pow(10, -7);
$kv = pow(10, -14);
$langt_udtryk = pow(sqrt(((2 * pow($ks, 2) * pow($kv, 2)) / 27) - ((pow($ks, 4) * pow($cs, 2)) / 108) - ((5 * pow($ks, 3) * $kv * $cs) / 27) - ((pow($ks, 3) * pow($cs, 3)) / 27) - ((pow($ks, 4) * $kv) / 27) - ((pow($ks, 2) * $kv * pow($cs, 2)) / 9) - (($ks * pow($kv, 2) * $cs) / 9) - (pow($kv, 3) / 27)) - (pow($ks, 3) / 27) - ((pow($ks, 2) * $cs) / 6) + (($ks * $kv) / 3), (1 / 3));
var_dump($langt_udtryk);
$x = (((pow($ks, 2) / 9) + (($cs * $ks) / 3) + ($kv / 3)) / $langt_udtryk) - ($ks / 3) + $langt_udtryk;
var_dump($x);
$ph = -log10($x);
var_dump($ph);
Og outputtet er følgende:
Langt udtryk: float(NAN)
x: float(NAN)
pH: float(NAN)
Hvis jeg derimod erstatter sqrt i ovenstående udtryk med bcsqrt er outputtet følgende:
Langt udtryk: float(6.53924680941E-8)
x: float(1.05122255286E-7)
pH: float(6.97830533036)
Jeg har lavet den samme beregning manuelt med henblik på at kontrollere resultatet - og jeg får følgende resultater:
x = 1,025 * 10^-7
pH = 6,989
Afvigelsen ude på 2. decimal skyldes formodentlig blot afrunding, så det må siges at være acceptabelt. Så langt, så godt - jeg fik noget der lignede det, jeg gerne ville have.
Derimod bliver det rigtig mystisk, når jeg giver $ks andre værdier - eksempelvis:
$ks = 1.738 * pow(10, -5);
Nu får jeg nemlig - selv ved brug af bcsqrt() - følgende output:
Langt udtryk: float(NAN)
x: float(NAN)
pH: float(NAN)
Ifølge mine manuelle beregninger burde output være:
x = 1,051 * 10^-7
pH = 6,978
Er der nogen der ved, hvad det kan skyldes?
På forhånd mange tak. Al hjælp er værdsat!
18. marts 2011 - 11:47
#3
@intenz: Mange tak for dit svar. Du har selvfølgelig ret - det er i PHP ikke umiddelbart muligt at tage kvadratroden af et negativt tal, da PHP ikke kan håndtere imaginære tal. Du får selvfølgelig point for din observation - og det i øvrigt helt korrekte svar på, hvorfor output er NAN.
Det afføder dog et nyt problem. Formlen er nemlig korrekt. Jeg kan desværre ikke blot efter forgodtbefindende ændre fortegn - hvorfor det desværre ikke er en mulighed at tage den absolutte værdi af tallet. Min manuelle kontrolberegning er udført i MathCad - som også kan regne med komplekse (dvs. imaginære) tal. Kontrolberegningen i MathCad viser, at "langt udtryk" i MathCad bliver imaginær, hvis jeg udskriver værdien:
Langt udtryk = 2,142 * 10^-7 + 1,24i * 10^-7
Og i PHP:
Langt udtryk = float(NAN)
Da dette blot er en midlertidig variabel (som er til for overskuelighedens skyld) er det ikke problematisk at tallet bliver imaginært, idet slutresultaterne (x og pH) bliver fine reelle tal:
x = 1,051 * 10^-7
pH = 6,978
Mit problem er således ikke af matematisk karakter - at jeg får et imaginært tal. Mit problem er derimod - så vidt jeg nu kan se - at PHP ikke kan håndtere imaginære tal. Jeg har forgæves kigget på nogle classes, men uden helt at finde hvad jeg søgte.
Men foreløbig mange tak! Yderligere input er meget velkomne.
19. marts 2011 - 15:19
#5
@intenz: Tak for tippet. Jeg har i mellemtiden set nærmere på de to muligheder - og min umiddelbare konklusion er, at førstnævnte ser ud til at være lettest at gå til. Der ser ud til at være et væld af muligheder i PEAR, men den er temmelig dårligt dokumenteret - og da jeg endnu ikke har særlig meget erfaring med objektorienteret programmering vil jeg i første omgang ty til den mest veldokumenterede. Der medfølger nemlig bl.a. en sample.php - med en række eksempler på brug af klassen. Jeg melder tilbage, når jeg har gjort mig nogle erfaringer. Foreløbig mange tak!
19. marts 2011 - 21:36
#6
Det ser umiddelbart brugbart ud - jeg er i stand til at udføre simple beregninger ved brug af den første PHP-klasse. Så langt, så godt. Desværre kommer jeg nu matematisk til kort, idet klassen ikke indeholder nogen potensfunktion - svarende til PHP's indbyggede pow-funktion, som desværre kun kan håndtere reelle tal. Jeg kunne ikke umiddelbart google mig til svaret på, hvad z^(1/3) er.