1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
if not modules then modules = { } end modules ['util-rnd'] = {
version = 1.001,
comment = "companion to luat-lib.mkiv",
author = "Tamara, Adriana, Tomáš Hála & Hans Hagen",
copyright = "ConTeXt Development Team", -- umbrella
license = "see context related readme files"
}
-- The rounding code is a variant on Tomáš Hála <tomas.hala@mendelu.cz; mendelu@thala.cz>
-- code that is used in the statistical module. We use local variables and a tolerant name
-- resolver that also permits efficient local aliases. With code like this one
-- really have to make sure that locals are used because changing the rounding
-- can influence other code.
local floor, ceil, pow = math.floor, math.ceil, math.pow
local rawget, type = rawget, type
local gsub, lower = string.gsub, string.lower
local rounding = { }
local methods = {
no = function(num)
-- no rounding
return num
end,
up = function(num,coef)
-- ceiling rounding
coef = coef and pow(10,coef) or 1
return ceil(num * coef) / coef
end,
down = function(num,coef)
-- floor rounding
coef = coef and pow(10,coef) or 1
return floor(num * coef) / coef
end,
halfup = function(num,coef)
-- rounds decimal numbers as usual, numbers with 0.5 up, too (e.g. number -0.5 will be rounded to 0)
coef = coef and pow(10,coef) or 1
return floor(num * coef + 0.5) / coef
end,
halfdown = function(num,coef)
-- rounds decimal numbers as usual, numbers with 0.5 down, too (e.g. number 0.5 will be rounded to 0)
coef = coef and pow(10,coef) or 1
return ceil(num * coef -0.5) / coef
end,
halfabsup = function(num,coef)
-- rounds deciaml numbers as usual, numbers with 0.5 away from zero, e.g. numbers -0.5 and 0.5 will be rounded to -1 and 1
coef = coef and pow(10,coef) or 1
return (num >= 0 and floor(num * coef + 0.5) or ceil(num * coef - 0.5)) / coef
end,
halfabsdown = function(num,coef)
-- rounds deciaml numbers as usual, numbers with 0.5 towards zero, e.g. numbers -0.5 and 0.5 will be rounded both to 0
coef = coef and pow(10,coef) or 1
return (num < 0 and floor(num * coef + 0.5) or ceil(num * coef - 0.5)) / coef
end,
halfeven = function(num,coef)
-- rounds deciaml numbers as usual, numbers with 0.5 to the nearest even, e.g. numbers 1.5 and 2.5 will be rounded both to 2
coef = coef and pow(10,coef) or 1
num = num*coef
return floor(num + (((num - floor(num)) ~= 0.5 and 0.5) or ((floor(num) % 2 == 1) and 1) or 0)) / coef
end,
halfodd = function(num,coef)
-- rounds deciaml numbers as usual, numbers with 0.5 to the nearest odd (e.g. numbers 1.5 and 2.5 will be rounded to 1 and 3
coef = coef and pow(10,coef) or 1
num = num * coef
return floor(num + (((num - floor(num)) ~= 0.5 and 0.5) or ((floor(num) % 2 == 1) and 0) or 1)) / coef
end,
}
methods.default = methods.halfup
rounding.methods = table.setmetatableindex(methods,function(t,k)
local s = gsub(lower(k),"[^a-z]","")
local v = rawget(t,s)
if not v then
v = t.halfup
end
t[k] = v
return v
end)
-- If needed I can make a high performance one.
local defaultmethod = methods.halfup
rounding.round = function(num,dec,mode)
if type(dec) == "string" then
mode = dec
dec = 1
end
return (mode and methods[mode] or defaultmethods)(num,dec)
end
number.rounding = rounding
-- -- Tomáš' test numbers:
-- local list = { 5.49, 5.5, 5.51, 6.49, 6.5, 6.51, 0.5, 12.45 }
--
-- for method, round in table.sortedhash(number.rounding.methods) do
-- for i=1,#list do
-- local n = list[i]
-- print(n,method,round(n,k),round(n,k,3))
-- end
-- end
--
-- local myround = number.rounding.methods["HALF ABS DOWN"]
--
-- for i=1,#list do
-- local n = list[i]
-- print(n,"Half Abs Down",number.rounding.round(n,1,"Half Abs Down"))
-- print(n,"HALF_ABS_DOWN",number.rounding.round(n,1,"HALF_ABS_DOWN"))
-- print(n,"HALF_ABS_DOWN",myround(n,1))
-- end
return rounding
|