Skip to content

Commit f852688

Browse files
committed
Bypass floating point rounding issues on i686 platform
Discovered on ubuntu i686 wheel building, can be reproduced with: $ docker run -it --rm -v $PWD:/srv quay.io/pypa/manylinux2010_i686:2021-02-06-3d322a5 $ cd srv $ /opt/python/cp38-cp38/bin/python -m pip install .[test] $ /opt/python/cp38-cp38/bin/python -m pytest
1 parent 145ef99 commit f852688

File tree

1 file changed

+126
-76
lines changed

1 file changed

+126
-76
lines changed

tests/test_core.py

Lines changed: 126 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,9 @@ def evaluate(expr, variables, parameters):
196196
assert evaluate("1+3/2*4", [], []) == 1 + 3.0 / 2.0 * 4.0
197197
assert evaluate("1+4*(3/2+5)", [], []) == 1 + 4 * (3.0 / 2.0 + 5.0)
198198
assert evaluate("1+2*3/4*5", [], []) == 1 + 2.0 * 3.0 / 4.0 * 5
199-
assert evaluate("1+2*3/(4+5)+6", [], []) == 1 + 2.0 * 3.0 / (4 + 5) + 6
199+
assert evaluate("1+2*3/(4+5)+6", [], []) == pytest.approx(
200+
1 + 2.0 * 3.0 / (4 + 5) + 6, abs=1e-15
201+
) # i686 mystery
200202
assert evaluate("100./3.*2+1", [], []) == 100.0 / 3.0 * 2.0 + 1
201203
assert evaluate("100./3.*(4-2)+2*(3+1)", [], []) == 100.0 / 3.0 * (4 - 2) + 2 * (
202204
3 + 1
@@ -257,10 +259,9 @@ def evaluate(expr, variables, parameters):
257259
# assert evaluate("TMath::ATanH(0.5)", [], []) == math.atanh(0.5)
258260
assert evaluate("max(max(5,3),2)", [], []) == 5.0
259261
assert evaluate("max(2,max(5,3))", [], []) == 5.0
260-
assert (
261-
evaluate("-(-2.36997+0.413917*log(208))/208", [], [])
262-
== -(-2.36997 + 0.413917 * math.log(208.0)) / 208.0
263-
)
262+
assert evaluate("-(-2.36997+0.413917*log(208))/208", [], []) == pytest.approx(
263+
-(-2.36997 + 0.413917 * math.log(208.0)) / 208.0, abs=1e-15
264+
) # i686 mystery
264265

265266
for x in [1.0, 2.0, 3.0]:
266267
assert evaluate("2*erf(4*(x-1))", [x], []) == 2 * math.erf(4 * (x - 1))
@@ -272,25 +273,32 @@ def evaluate(expr, variables, parameters):
272273
"([0]+([1]/((log10(x)^2)+[2])))+([3]*exp(-([4]*((log10(x)-[5])*(log10(x)-[5])))))",
273274
[x],
274275
v,
275-
) == (
276-
v[0]
277-
+ (
278-
v[1]
279-
/ (((math.log(x) / math.log(10)) * (math.log(x) / math.log(10))) + v[2])
276+
) == pytest.approx(
277+
(
278+
v[0]
279+
+ (
280+
v[1]
281+
/ (
282+
((math.log(x) / math.log(10)) * (math.log(x) / math.log(10)))
283+
+ v[2]
284+
)
285+
)
280286
)
281-
) + (
282-
v[3]
283-
* math.exp(
284-
-1.0
285-
* (
286-
v[4]
287+
+ (
288+
v[3]
289+
* math.exp(
290+
-1.0
287291
* (
288-
(math.log(x) / math.log(10.0) - v[5])
289-
* (math.log(x) / math.log(10.0) - v[5])
292+
v[4]
293+
* (
294+
(math.log(x) / math.log(10.0) - v[5])
295+
* (math.log(x) / math.log(10.0) - v[5])
296+
)
290297
)
291298
)
292-
)
293-
)
299+
),
300+
abs=1e-15,
301+
) # i686
294302

295303
v = [1.3, 4.0, 2.0]
296304
for x in [1.0, 10.0, 100.0]:
@@ -312,13 +320,13 @@ def evaluate(expr, variables, parameters):
312320
) == max(0.0001, 1 - y * (v[0] + (v[1] * z) * (1 + v[2] * math.log(x))) / x)
313321

314322
for x in [0.1, 1.0, 10.0, 100.0]:
315-
assert (
316-
evaluate(
317-
"(-2.36997+0.413917*log(x))/x-(-2.36997+0.413917*log(208))/208", [x], []
318-
)
319-
== (-2.36997 + 0.413917 * math.log(x)) / x
320-
- (-2.36997 + 0.413917 * math.log(208)) / 208
321-
)
323+
assert evaluate(
324+
"(-2.36997+0.413917*log(x))/x-(-2.36997+0.413917*log(208))/208", [x], []
325+
) == pytest.approx(
326+
(-2.36997 + 0.413917 * math.log(x)) / x
327+
- (-2.36997 + 0.413917 * math.log(208)) / 208,
328+
abs=1e-15,
329+
) # i686
322330
assert (
323331
evaluate(
324332
"max(0.,1.03091-0.051154*pow(x,-0.154227))-max(0.,1.03091-0.051154*pow(208.,-0.154227))",
@@ -334,13 +342,12 @@ def evaluate(expr, variables, parameters):
334342
assert evaluate("[2]*([3]+[4]*log(max([0],min([1],x))))", [x], v) == v[2] * (
335343
v[3] + v[4] * math.log(max(v[0], min(v[1], x)))
336344
)
337-
assert (
338-
evaluate(
339-
"((x>=[6])*(([0]+([1]/((log10(x)^2)+[2])))+([3]*exp(-([4]*((log10(x)-[5])*(log10(x)-[5])))))))+((x<[6])*[7])",
340-
[x],
341-
v,
342-
)
343-
== (
345+
assert evaluate(
346+
"((x>=[6])*(([0]+([1]/((log10(x)^2)+[2])))+([3]*exp(-([4]*((log10(x)-[5])*(log10(x)-[5])))))))+((x<[6])*[7])",
347+
[x],
348+
v,
349+
) == pytest.approx(
350+
(
344351
(x >= v[6])
345352
* (
346353
(
@@ -371,40 +378,50 @@ def evaluate(expr, variables, parameters):
371378
)
372379
)
373380
)
374-
+ ((x < v[6]) * v[7])
375-
)
381+
+ ((x < v[6]) * v[7]),
382+
abs=1e-15,
383+
) # i686
376384
assert evaluate(
377385
"(max(0.,1.03091-0.051154*pow(x,-0.154227))-max(0.,1.03091-0.051154*pow(208.,-0.154227)))+[7]*((-2.36997+0.413917*log(x))/x-(-2.36997+0.413917*log(208))/208)",
378386
[x],
379387
v,
380-
) == (
381-
max(0.0, 1.03091 - 0.051154 * math.pow(x, -0.154227))
382-
- max(0.0, 1.03091 - 0.051154 * math.pow(208.0, -0.154227))
383-
) + v[
384-
7
385-
] * (
386-
(-2.36997 + 0.413917 * math.log(x)) / x
387-
- (-2.36997 + 0.413917 * math.log(208)) / 208
388-
)
389-
assert evaluate(
390-
"[2]*([3]+[4]*log(max([0],min([1],x))))*1./([5]+[6]*100./3.*(max(0.,1.03091-0.051154*pow(x,-0.154227))-max(0.,1.03091-0.051154*pow(208.,-0.154227)))+[7]*((-2.36997+0.413917*log(x))/x-(-2.36997+0.413917*log(208))/208))",
391-
[x],
392-
v,
393-
) == v[2] * (v[3] + v[4] * math.log(max(v[0], min(v[1], x)))) * 1.0 / (
394-
v[5]
395-
+ v[6]
396-
* 100.0
397-
/ 3.0
398-
* (
388+
) == pytest.approx(
389+
(
399390
max(0.0, 1.03091 - 0.051154 * math.pow(x, -0.154227))
400391
- max(0.0, 1.03091 - 0.051154 * math.pow(208.0, -0.154227))
401392
)
402393
+ v[7]
403394
* (
404395
(-2.36997 + 0.413917 * math.log(x)) / x
405396
- (-2.36997 + 0.413917 * math.log(208)) / 208
406-
)
407-
)
397+
),
398+
abs=1e-15,
399+
) # i686
400+
assert evaluate(
401+
"[2]*([3]+[4]*log(max([0],min([1],x))))*1./([5]+[6]*100./3.*(max(0.,1.03091-0.051154*pow(x,-0.154227))-max(0.,1.03091-0.051154*pow(208.,-0.154227)))+[7]*((-2.36997+0.413917*log(x))/x-(-2.36997+0.413917*log(208))/208))",
402+
[x],
403+
v,
404+
) == pytest.approx(
405+
v[2]
406+
* (v[3] + v[4] * math.log(max(v[0], min(v[1], x))))
407+
* 1.0
408+
/ (
409+
v[5]
410+
+ v[6]
411+
* 100.0
412+
/ 3.0
413+
* (
414+
max(0.0, 1.03091 - 0.051154 * math.pow(x, -0.154227))
415+
- max(0.0, 1.03091 - 0.051154 * math.pow(208.0, -0.154227))
416+
)
417+
+ v[7]
418+
* (
419+
(-2.36997 + 0.413917 * math.log(x)) / x
420+
- (-2.36997 + 0.413917 * math.log(208)) / 208
421+
)
422+
),
423+
abs=1e-15,
424+
) # i686
408425

409426
assert (
410427
evaluate("100./3.*0.154227+2.36997", [], []) == 100.0 / 3.0 * 0.154227 + 2.36997
@@ -441,23 +458,26 @@ def evaluate(expr, variables, parameters):
441458
"max(0.0001,[0]+[1]/(pow(log10(x),2)+[2])+[3]*exp(-[4]*(log10(x)-[5])*(log10(x)-[5])))",
442459
[x],
443460
v,
444-
) == max(
445-
0.0001,
446-
v[0]
447-
+ v[1] / (math.pow(math.log(x) / math.log(10), 2) + v[2])
448-
+ v[3]
449-
* math.exp(
450-
-v[4]
451-
* (math.log(x) / math.log(10) - v[5])
452-
* (math.log(x) / math.log(10) - v[5])
461+
) == pytest.approx(
462+
max(
463+
0.0001,
464+
v[0]
465+
+ v[1] / (math.pow(math.log(x) / math.log(10), 2) + v[2])
466+
+ v[3]
467+
* math.exp(
468+
-v[4]
469+
* (math.log(x) / math.log(10) - v[5])
470+
* (math.log(x) / math.log(10) - v[5])
471+
),
453472
),
454-
)
473+
abs=1e-15,
474+
) # i686
455475

456476
v = [0.945459, 2.78658, 1.65054, -48.1061, 0.0287239, -10.8759]
457477
for x in [425.92155818]:
458-
assert evaluate("-[4]*(log10(x)-[5])*(log10(x)-[5])", [x], v) == -v[4] * (
459-
math.log10(x) - v[5]
460-
) * (math.log10(x) - v[5])
478+
assert evaluate("-[4]*(log10(x)-[5])*(log10(x)-[5])", [x], v) == pytest.approx(
479+
-v[4] * (math.log10(x) - v[5]) * (math.log10(x) - v[5]), abs=1e-15
480+
) # i686
461481

462482
v = [55, 2510, 0.997756, 1.000155, 0.979016, 0.001834, 0.982, -0.048, 1.250]
463483
x = 100.0
@@ -554,9 +574,9 @@ def evaluate(expr, variables, parameters):
554574

555575
v = [0.006467, 0.02519, 77.08]
556576
for x in [100.0]:
557-
assert evaluate("[0]+[1]*exp(-x/[2])", [x], v) == v[0] + v[1] * math.exp(
558-
-x / v[2]
559-
)
577+
assert evaluate("[0]+[1]*exp(-x/[2])", [x], v) == pytest.approx(
578+
v[0] + v[1] * math.exp(-x / v[2]), abs=1e-15
579+
) # i686
560580

561581
v = [1.4, 0.453645, -0.015665]
562582
x, y, z = 157.2, 0.5, 23.2
@@ -580,9 +600,12 @@ def evaluate(expr, variables, parameters):
580600
x = 100.0
581601
assert evaluate(
582602
"sqrt([0]*abs([0])/(x*x)+[1]*[1]*pow(x,[3])+[2]*[2])", [x], v
583-
) == math.sqrt(
584-
v[0] * abs(v[0]) / (x * x) + v[1] * v[1] * math.pow(x, v[3]) + v[2] * v[2]
585-
)
603+
) == pytest.approx(
604+
math.sqrt(
605+
v[0] * abs(v[0]) / (x * x) + v[1] * v[1] * math.pow(x, v[3]) + v[2] * v[2]
606+
),
607+
abs=1e-15,
608+
) # i686
586609

587610
v = [2.3, 0.20, 0.009]
588611
x = 100.0
@@ -908,3 +931,30 @@ def test_transform():
908931
assert corr.evaluate(2) == 0.0
909932
with pytest.raises(IndexError):
910933
corr.evaluate(3)
934+
935+
936+
def evaluate(expr, variables, parameters):
937+
cset = {
938+
"schema_version": 2,
939+
"corrections": [
940+
{
941+
"name": "test",
942+
"version": 1,
943+
"inputs": [
944+
{"name": vname, "type": "real"}
945+
for vname, _ in zip("xyzt", variables)
946+
],
947+
"output": {"name": "f", "type": "real"},
948+
"data": {
949+
"nodetype": "formula",
950+
"expression": expr,
951+
"parser": "TFormula",
952+
"variables": [vname for vname, _ in zip("xyzt", variables)],
953+
"parameters": parameters or None,
954+
},
955+
}
956+
],
957+
}
958+
schema.CorrectionSet.parse_obj(cset)
959+
corr = core.CorrectionSet.from_string(json.dumps(cset))["test"]
960+
return corr.evaluate(*variables)

0 commit comments

Comments
 (0)