[php] strange calculation with float values

Custom Title Activated
Loyal Member
Joined
Nov 28, 2004
Messages
2,236
Reaction score
0
I am making a serious calculation app for my homework for calculating cubic spline.

Well, everything is working, except when I try to calculate difference between two values, I get strange results:

Code:
f(function)(1.1) = 0.12831732399
f(spline)(1.1) = 0.12831732399
|delta(f(1.1))| = 1.00003338943E-013 [ abs(abs($value_spline)-abs($value_function)) ];

well, I did not understood at first, what happening, because numbers seem to be equal.. then I tried to see the serialized state of them and got this:
Code:
$value_function=0.12831732399049775494859204627573490142822265625;
$value_spline=0.1283173239904190854332455273834057152271270751953125;
$value_delta=1.000033389431109753786586225032806396484375E-13;

I was so desperate I even tried to convert the values to string, then substr some and then proceed the calculation, but resulted the same ....E...

I don't even know what type of number is with that 'E'..

Any suggestions?
 
Lahey - Floating point
What Every Computer Scientist Should Know About Floating-Point Arithmetic

Wait a moment... why are you using PHP? I don't see any serverside-scripting here.
oky, that's lots of reading... and it's for C

I use PHP for the app because it's fastest way to produce an app and I do not tend to do anything but show how I understand cubic spline interpolation and am able to use it with any language. But that's not a point.

okey, I'll explain if anyone is willing to help me with the problem.

I acquire following values (using methods which are not really needed to be mentioned here, cuz that's not one hundred of lines..):
$value_function = 0.12831732399;
$value_spline = 0.12831732399;

then I need to find the difference between those two values with the formula:
$value_delta = abs(abs($value_spline)-abs($value_function));

And my problem is that it returns something like 1.00003338943E-013

I even tried to round $value_function and $value_spline up to 13 numbers after point, but it still resulted that 'E'..
 
I'm no math genius, but E usally means exponent. So basically 1.00003338943E-013 = 1.00003338943^(10*-.013)
Have you tried calculating it out on paper or with a calculator or MAPLE with standard values?
 
thecircusb0y is right.

If it is a problem with roundoff, there are certain techniques to prevent it. I spend a whole course once on the subject of computational mathematics for this type'a thing, and it basicly comes down to your method of computation for both values (spline and delta). What happens is that the first 9 figures or so are correct, but somewhere further down they differ by a very small amount: 0,00000000000100003338943 to be precise.

To fix this, you can use the round() function (ie, round(spline, 5)), then they will be equal if you subtract them from eachother :)
 
Last edited:
ok, so I use this:
PHP:
$value_delta = abs(round(abs($value_spline), 11) - round(abs($value_function), 11));

when
PHP:
$value_function = 0.12831732399049775494859204627573490142822265625;
$value_spline = 0.1282540015542851019603176609962247312068939208984375;

I get
6.332244E-005
or in serialized form:
6.3322440000013191507832743809558451175689697265625E-5;

when I change round(,11) to e.g. 9, I receive the following result:
6.3322E-005
or serialized:
6.33220000000045413202087729587219655513763427734375E-5

and with 5:
7E-005

I would like to have my result with minimum 11 values after point.
 
Your values simply aren't accurate enough. With those function and spline values you should round(value, 4) to get the correct result I think.

What functions do you use to get those values? Because obviously you used an inaccurate calculation form there.
 
ok, I can't just copy/paste the whole application here, because it's currently is a matter of a copyright and I know that at least 100ppl who got same task are willing to put their hands on my code, so I will post only the part where this occurs:

This is a function which solves 'function', 'spline' and calculates 'difference' between them:
PHP:
function math_spline_cubic_values($function_real, $function_spline, $x)
{
	//find 'x' in function
	eval('$value_function = (double) ' . str_replace('[$i]', '', $function_real) . ';' );
	
	
	//find appropriate function for 'x' and then evaluate it with given 'x'
	for($i=0; $i<=count($function_spline)-1; $i++)
	{
		if ( ($function_spline[$i]['a'] <= $x) && ($x <= $function_spline[$i]['b']) )
		{
			eval('$value_spline = (double) ' . str_replace('[$i]', '', $function_spline[$i]['function']) . ';' );
			break;
		}
	}
	
	//find delta
	$value_delta = (double) abs(round(abs($value_spline), 13) - round(abs($value_function), 13));
	
	return array($value_function, $value_spline, $value_delta);
}

now the data I pass to function is quite messy, but it is correct, because I was making this app according to a book and all given examples were solved successfully. I give data in serialized form:
PHP:
$x = 1.1;
$function_real = unserialize('s:26:"($x[$i]+2) * log10($x[$i])";');
$function_spline = unserialize('a:40:{i:0;a:3:{s:8:"function";s:88:"0 + 1.29044037097 * ($x - 1) + 0 * pow(($x - 1), 2) + -0.726713106562 * pow(($x - 1), 3)";s:1:"a";d:1;s:1:"b";d:1.100000000000000088817841970012523233890533447265625;}i:1;a:3:{s:8:"function";s:119:"0.12831732399 + 1.26863897777 * ($x - 1.1) + -0.218013931969 * pow(($x - 1.1), 2) + 0.378904904216 * pow(($x - 1.1), 3)";s:1:"a";d:1.100000000000000088817841970012523233890533447265625;s:1:"b";d:1.19999999999999996447286321199499070644378662109375;}i:2;a:3:{s:8:"function";s:121:"0.253379987352 + 1.23640333851 * ($x - 1.2) + -0.104342460704 * pow(($x - 1.2), 2) + 0.0361660165529 * pow(($x - 1.2), 3)";s:1:"a";d:1.19999999999999996447286321199499070644378662109375;s:1:"b";d:1.3000000000000000444089209850062616169452667236328125;}i:3;a:3:{s:8:"function";s:121:"0.376013062613 + 1.21661982686 * ($x - 1.3) + -0.093492655738 * pow(($x - 1.3), 2) + 0.0952025645982 * pow(($x - 1.3), 3)";s:1:"a";d:1.3000000000000000444089209850062616169452667236328125;s:1:"b";d:1.399999999999999911182158029987476766109466552734375;}i:4;a:3:{s:8:"function";s:122:"0.496835321306 + 1.20077737265 * ($x - 1.4) + -0.0649318863585 * pow(($x - 1.4), 2) + 0.0556669871952 * pow(($x - 1.4), 3)";s:1:"a";d:1.399999999999999911182158029987476766109466552734375;s:1:"b";d:1.5;}i:5;a:3:{s:8:"function";s:117:"0.616319406695 + 1.189461005 * ($x - 1.5) + -0.0482317902 * pow(($x - 1.5), 2) + 0.0487482687641 * pow(($x - 1.5), 3)";s:1:"a";d:1.5;s:1:"b";d:1.600000000000000088817841970012523233890533447265625;}i:6;a:3:{s:8:"function";s:122:"0.734831937561 + 1.18127709502 * ($x - 1.6) + -0.0336073095707 * pow(($x - 1.6), 2) + 0.0374351320181 * pow(($x - 1.6), 3)";s:1:"a";d:1.600000000000000088817841970012523233890533447265625;s:1:"b";d:1.70000000000000017763568394002504646778106689453125;}i:7;a:3:{s:8:"function";s:120:"0.8526610091 + 1.17567868707 * ($x - 1.7) + -0.0223767699653 * pow(($x - 1.7), 2) + 0.0304092859892 * pow(($x - 1.7), 3)";s:1:"a";d:1.70000000000000017763568394002504646778106689453125;s:1:"b";d:1.8;}i:8;a:3:{s:8:"function";s:122:"0.970035519393 + 1.17211561165 * ($x - 1.8) + -0.0132539841685 * pow(($x - 1.8), 2) + 0.0245029998802 * pow(($x - 1.8), 3)";s:1:"a";d:1.8;s:1:"b";d:1.9;}i:9;a:3:{s:8:"function";s:122:"1.08713904372 + 1.17019990482 * ($x - 1.9) + -0.00590308420447 * pow(($x - 1.9), 2) + 0.0199793003919 * pow(($x - 1.9), 3)";s:1:"a";d:1.9;s:1:"b";d:2;}i:10;a:3:{s:8:"function";s:116:"1.20411998266 + 1.16961866699 * ($x - 2) + 9.07059131024E-005 * pow(($x - 2), 2) + 0.016351995382 * pow(($x - 2), 3)";s:1:"a";d:2;s:1:"b";d:2.100000000000000088817841970012523233890533447265625;}i:11;a:3:{s:8:"function";s:119:"1.32109910841 + 1.17012736803 * ($x - 2.1) + 0.0049963045277 * pow(($x - 2.1), 2) + 0.013451195881 * pow(($x - 2.1), 3)";s:1:"a";d:2.100000000000000088817841970012523233890533447265625;s:1:"b";d:2.20000000000000017763568394002504646778106689453125;}i:12;a:3:{s:8:"function";s:121:"1.43817525945 + 1.17153016481 * ($x - 2.2) + 0.00903166329199 * pow(($x - 2.2), 2) + 0.0111023082271 * pow(($x - 2.2), 3)";s:1:"a";d:2.20000000000000017763568394002504646778106689453125;s:1:"b";d:2.29999999999999982236431605997495353221893310546875;}i:13;a:3:{s:8:"function";s:121:"1.55542969488 + 1.17366956672 * ($x - 2.3) + 0.0123623557601 * pow(($x - 2.3), 2) + 0.00918842605865 * pow(($x - 2.3), 3)";s:1:"a";d:2.29999999999999982236431605997495353221893310546875;s:1:"b";d:2.4000000000000003552713678800500929355621337890625;}i:14;a:3:{s:8:"function";s:120:"1.67292946353 + 1.17641769065 * ($x - 2.4) + 0.0151188835777 * pow(($x - 2.4), 2) + 0.0076175921898 * pow(($x - 2.4), 3)";s:1:"a";d:2.4000000000000003552713678800500929355621337890625;s:1:"b";d:2.5;}i:15;a:3:{s:8:"function";s:121:"1.79073003902 + 1.17966999513 * ($x - 2.5) + 0.0174041612347 * pow(($x - 2.5), 2) + 0.00632051598732 * pow(($x - 2.5), 3)";s:1:"a";d:2.5;s:1:"b";d:2.600000000000000088817841970012523233890533447265625;}i:16;a:3:{s:8:"function";s:121:"1.90887740067 + 1.18334044286 * ($x - 2.6) + 0.0193003160309 * pow(($x - 2.6), 2) + 0.00524343525528 * pow(($x - 2.6), 3)";s:1:"a";d:2.600000000000000088817841970012523233890533447265625;s:1:"b";d:2.70000000000000017763568394002504646778106689453125;}i:17;a:3:{s:8:"function";s:120:"2.02740969155 + 1.18735780912 * ($x - 2.7) + 0.0208733466074 * pow(($x - 2.7), 2) + 0.0043445170401 * pow(($x - 2.7), 3)";s:1:"a";d:2.70000000000000017763568394002504646778106689453125;s:1:"b";d:2.79999999999999982236431605997495353221893310546875;}i:18;a:3:{s:8:"function";s:121:"2.14635855044 + 1.19166281396 * ($x - 2.8) + 0.0221767017195 * pow(($x - 2.8), 2) + 0.00359084947162 * pow(($x - 2.8), 3)";s:1:"a";d:2.79999999999999982236431605997495353221893310546875;s:1:"b";d:2.9000000000000003552713678800500929355621337890625;}i:19;a:3:{s:8:"function";s:119:"2.2657501897 + 1.19620587978 * ($x - 2.9) + 0.023253956561 * pow(($x - 2.9), 2) + 0.00295634944731 * pow(($x - 2.9), 3)";s:1:"a";d:2.9000000000000003552713678800500929355621337890625;s:1:"b";d:3;}i:20;a:3:{s:8:"function";s:114:"2.3856062736 + 1.20094536158 * ($x - 3) + 0.0241408613951 * pow(($x - 3), 2) + 0.00242018459568 * pow(($x - 3), 3)";s:1:"a";d:3;s:1:"b";d:3.100000000000000088817841970012523233890533447265625;}i:21;a:3:{s:8:"function";s:119:"2.50594463855 + 1.2058461394 * ($x - 3.1) + 0.0248669167738 * pow(($x - 3.1), 2) + 0.0019656013608 * pow(($x - 3.1), 3)";s:1:"a";d:3.100000000000000088817841970012523233890533447265625;s:1:"b";d:3.20000000000000017763568394002504646778106689453125;}i:22;a:3:{s:8:"function";s:120:"2.62677988726 + 1.21087849079 * ($x - 3.2) + 0.0254565971821 * pow(($x - 3.2), 2) + 0.0015790382909 * pow(($x - 3.2), 3)";s:1:"a";d:3.20000000000000017763568394002504646778106689453125;s:1:"b";d:3.300000000000000266453525910037569701671600341796875;}i:23;a:3:{s:8:"function";s:121:"2.74812388135 + 1.21601718138 * ($x - 3.3) + 0.0259303086694 * pow(($x - 3.3), 2) + 0.00124945098487 * pow(($x - 3.3), 3)";s:1:"a";d:3.300000000000000266453525910037569701671600341796875;s:1:"b";d:3.4000000000000003552713678800500929355621337890625;}i:24;a:3:{s:8:"function";s:122:"2.86998615203 + 1.22124072664 * ($x - 3.4) + 0.0263051439648 * pow(($x - 3.4), 2) + 0.000967794653402 * pow(($x - 3.4), 3)";s:1:"a";d:3.4000000000000003552713678800500929355621337890625;s:1:"b";d:3.5;}i:25;a:3:{s:8:"function";s:122:"2.99237424393 + 1.22653078927 * ($x - 3.5) + 0.0265954823608 * pow(($x - 3.5), 2) + 0.000726619390299 * pow(($x - 3.5), 3)";s:1:"a";d:3.5;s:1:"b";d:3.600000000000000088817841970012523233890533447265625;}i:26;a:3:{s:8:"function";s:121:"3.1152940043 + 1.23187168433 * ($x - 3.6) + 0.0268134681779 * pow(($x - 3.6), 2) + 0.000519770601783 * pow(($x - 3.6), 3)";s:1:"a";d:3.600000000000000088817841970012523233890533447265625;s:1:"b";d:3.70000000000000017763568394002504646778106689453125;}i:27;a:3:{s:8:"function";s:122:"3.23874982718 + 1.23724997108 * ($x - 3.7) + 0.0269693993585 * pow(($x - 3.7), 2) + 0.000342093998146 * pow(($x - 3.7), 3)";s:1:"a";d:3.70000000000000017763568394002504646778106689453125;s:1:"b";d:3.8000000000000003552713678800500929355621337890625;}i:28;a:3:{s:8:"function";s:122:"3.36274486038 + 1.24265411377 * ($x - 3.8) + 0.0270720275579 * pow(($x - 3.8), 2) + 0.000189426057325 * pow(($x - 3.8), 3)";s:1:"a";d:3.8000000000000003552713678800500929355621337890625;s:1:"b";d:3.9000000000000003552713678800500929355621337890625;}i:29;a:3:{s:8:"function";s:123:"3.48728118146 + 1.24807420207 * ($x - 3.9) + 0.0271288553751 * pow(($x - 3.9), 2) + 5.77511388049E-005 * pow(($x - 3.9), 3)";s:1:"a";d:3.9000000000000003552713678800500929355621337890625;s:1:"b";d:4;}i:30;a:3:{s:8:"function";s:118:"3.61235994797 + 1.25350170567 * ($x - 4) + 0.0271461807167 * pow(($x - 4), 2) + -5.43520132206E-005 * pow(($x - 4), 3)";s:1:"a";d:4;s:1:"b";d:4.0999999999999996447286321199499070644378662109375;}i:31;a:3:{s:8:"function";s:123:"3.73798152599 + 1.25892931126 * ($x - 4.1) + 0.0271298751128 * pow(($x - 4.1), 2) + -0.000155400284698 * pow(($x - 4.1), 3)";s:1:"a";d:4.0999999999999996447286321199499070644378662109375;s:1:"b";d:4.20000000000000017763568394002504646778106689453125;}i:32;a:3:{s:8:"function";s:123:"3.86414560047 + 1.26435062427 * ($x - 4.2) + 0.0270832550274 * pow(($x - 4.2), 2) + -0.000225293015682 * pow(($x - 4.2), 3)";s:1:"a";d:4.20000000000000017763568394002504646778106689453125;s:1:"b";d:4.300000000000000710542735760100185871124267578125;}i:33;a:3:{s:8:"function";s:123:"3.99085127015 + 1.26976051649 * ($x - 4.3) + 0.0270156671227 * pow(($x - 4.3), 2) + -0.000348959678671 * pow(($x - 4.3), 3)";s:1:"a";d:4.300000000000000710542735760100185871124267578125;s:1:"b";d:4.4000000000000003552713678800500929355621337890625;}i:34;a:3:{s:8:"function";s:123:"4.11809712951 + 1.27515318112 * ($x - 4.4) + 0.0269109792191 * pow(($x - 4.4), 2) + -0.000217876128294 * pow(($x - 4.4), 3)";s:1:"a";d:4.4000000000000003552713678800500929355621337890625;s:1:"b";d:4.5;}i:35;a:3:{s:8:"function";s:123:"4.24588133954 + 1.28052884068 * ($x - 4.5) + 0.0268456163806 * pow(($x - 4.5), 2) + -0.000990673219966 * pow(($x - 4.5), 3)";s:1:"a";d:4.5;s:1:"b";d:4.5999999999999996447286321199499070644378662109375;}i:36;a:3:{s:8:"function";s:120:"4.3742016891 + 1.28586824376 * ($x - 4.6) + 0.0265484144146 * pow(($x - 4.6), 2) + 0.00165055075164 * pow(($x - 4.6), 3)";s:1:"a";d:4.5999999999999996447286321199499070644378662109375;s:1:"b";d:4.70000000000000017763568394002504646778106689453125;}i:37;a:3:{s:8:"function";s:121:"4.50305564817 + 1.29122744317 * ($x - 4.7) + 0.0270435796401 * pow(($x - 4.7), 2) + -0.0084141282827 * pow(($x - 4.7), 3)";s:1:"a";d:4.70000000000000017763568394002504646778106689453125;s:1:"b";d:4.800000000000000710542735760100185871124267578125;}i:38;a:3:{s:8:"function";s:120:"4.63244041415 + 1.29638373525 * ($x - 4.8) + 0.0245193411553 * pow(($x - 4.8), 2) + 0.0289711066785 * pow(($x - 4.8), 3)";s:1:"a";d:4.800000000000000710542735760100185871124267578125;s:1:"b";d:4.9000000000000003552713678800500929355621337890625;}i:39;a:3:{s:8:"function";s:119:"4.7623529522 + 1.30215673668 * ($x - 4.9) + 0.0332106731588 * pow(($x - 4.9), 2) + -0.110702243863 * pow(($x - 4.9), 3)";s:1:"a";d:4.9000000000000003552713678800500929355621337890625;s:1:"b";d:5;}}');

The $x is a checkup of function and spline. If the system of spline functions is quite big, the $x should result the same or very similar result as calculated with real function and calculated from spline function system.

(On the whole, this part of app should show what's the difference and accuracy using cubic spline method compared with a real function.)
 
Last edited:
ok, I feel so not smart-a*s..
as far as I understand the calculations are ok, and everything is ok with that exponent in the answer. it's just very small number and it should be so... I shouldn't expect my app holds 0.00000000000000000000...1 in the memory as it's easier and more useful to write 1e-20
..
 
oky, that's lots of reading... and it's for C

I use PHP for the app because it's fastest way to produce an app and I do not tend to do anything but show how I understand cubic spline interpolation and am able to use it with any language. But that's not a point.
What I mean is, PHP is not suited for extensive numerical tasks like cubic spline interpolation, and thus it does not have the facilities for handling numerical calculations with as much accuracy and efficiency as other languages - as I alluded to in my first post, PHP is intended for serverside scripting, and its numerical capabilities were created for occasional use due to necessity of calculations on webpages, not extensive numerical tasks such as what you're doing. If I were you, I'd use a language like FORTRAN which was meant to do this type of task.

Another important point, never do a direct comparison between floating-point numbers. Due to their inherent inaccuracy this can result in two values not being equal when they should (which I think is your problem here.)

...and you don't have to write your own code to do cubic spline interpolation, there's plenty out there already. For example http://library.lanl.gov/numerical/bookfpdf.html (look under section 3.3... :))
 
well, I am fully capable of porting my current app to C but as I am not writing any 'real' app, just to show my level of understanding the method, my lang usage is fine.
I had compared my results with my mates' ones and found that the precision is equal, so I am not thinking it is non-capable to do difficult maths. of course, the main problem is speed, but for solving my task it's quite enough..

And is anyone still using fortran.. ;p?
 
By 'not suited for extensive numerical tasks' I meant that it didn't have the calculation precision you need:
[lexx] said:
I would like to have my result with minimum 11 values after point.
In fact, it notes in the PHP manual (PHP: Floating point numbers - Manual) itself the fallacies of using floating-point numbers and also
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (that's 64 bit IEEE format).
...only approximately 14 decimal digits are retained. For one calculation that's fine, but you're doing *many*, and thus the accumulation of error becomes such that retaining 14 digits is not enough.

...and Fortran is still being used, not so much in the mainstream app production, but in more advanced fields of scientific research and mathematics.
 
Last edited:
Back