- Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathnumber.lua
More file actions
Latest commit
131 lines (120 loc) · 4.24 KB
/
Copy pathnumber.lua
File metadata and controls
131 lines (120 loc) · 4.24 KB
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
-- number metatable
localmath=require'ext.math'
-- flatten ext.math into this just like we flatten lua's string into ext.string
localhasutf8, utf8=pcall(require, 'utf8')
localnumber= {}
number.__index=number
fork,vinpairs(math) donumber[k] =math[k] end
-- [[ tostring machine precision of arbitrary base
number.alphabets= {
{('0'):byte(), ('9'):byte()}, -- latin numbers
{('a'):byte(), ('z'):byte()}, -- english
{0x3b1, 0x3c9}, -- greek
{0x430, 0x45f}, -- cyrillic
{0x561, 0x586}, -- armenian
{0x905, 0x939}, -- devanagari
{0x2f00, 0x2fd5}, -- kangxi
{0x3041, 0x3096}, -- hiragana
{0x30a1, 0x30fa}, -- katakana
{0x4e00, 0x9fd0}, -- chinese, japanese, korean characters
}
functionnumber.charfor(digit)
localtable=require'ext.table'
for_,alphabetinipairs(number.alphabets) do
localstart,fin=table.unpack(alphabet)
ifdigit<=fin-startthen
digit=digit+start
ifhasutf8then
returnutf8.char(digit)
else
-- TODO this will fail with utf8 chars beyond ascii
returnstring.char(digit)
end
end
digit=digit- (fin-start+1)
end
error'you need more alphabets to represent that many digits'
end
-- TODO rename above function to 'tochar' ?
functionnumber.todigit(ch)
localtable=require'ext.table'
localindexInAlphabet
ifhasutf8then
indexInAlphabet=utf8.codepoint(ch)
else
-- TODO this will fail with utf8 chars beyond ascii
indexInAlphabet=string.byte(ch)
end
locallastTotalIndex=0
for_,alphabetinipairs(number.alphabets) do
localstart,fin=table.unpack(alphabet)
ifindexInAlphabet>=startandindexInAlphabet<=finthen
returnlastTotalIndex+ (indexInAlphabet-start)
end
lastTotalIndex=lastTotalIndex+ (fin-start+1)
end
error"couldn't find the character in all the alphabets"
end
number.base=10
number.maxdecimals=50
-- I'm not going to set this as __tostring by default, but I will leave it as part of the meta
-- feel free to use it with a line something like (function(m)m.__tostring=m.tostring end)(debug.getmetatable(0))
number.tostring=function(t, base, maxdecimals)
locals= {}
ift<0then
t=-t
table.insert(s, '-')
end
ift==0then
table.insert(s, '0')
table.insert(s, '.')
else
ifnotbasethenbase=number.baseend
ifnotmaxdecimalsthenmaxdecimals=number.maxdecimalsend
locali=math.floor(math.log(t,base))+1
ifi==math.hugethenerror'infinite number of digits' end
t=t/base^i
localdot
whiletruedo
ifi<1then
ifnotdotthen
dot=true
table.insert(s, '.')
ifi<0then
table.insert(s, ('0'):rep(-i))
end
end
ift==0thenbreakend
ifi<=-maxdecimalsthenbreakend
end
t=t*base
localdigit=math.floor(t)
t=t-digit
-- at this point 'digit' holds an integer value in [0,base)
-- there's two ways we can go about it:
-- 1) traditionally, where each digit represents an integer, times some base^i for some i
-- in this case, for fractional bases, the last (fraction) digit is only considered up to the fraction
-- i.e. in base 2.5, from 0b..1b we have the span of 1, partitioned by digits 0.1b at 2/5ths the distance, 0.2b at 4/5ths the distance, and 1.0 and 5/5ths the distance
-- from 1b..2b we have the same span,
-- and from 2b..10b we have half that span, from 2 to 2.5
-- therefore the value 2.2b would represent 2.8, which is also represetned by 10.0112210002002002...
-- so as long as the span between digits can represent fractions of base^i rather than whole base^i's
-- we can have multiple representations of numbers
-- 2) stretched. in this case a fractional span, such as from 2b to 10b in base 2.5, would be stretched
-- this is harder to convey when descibing the number system
table.insert(s, number.charfor(digit))
i=i-1
end
end
ifs[#s] =='.' thens[#s] =nilend
returntable.concat(s)
end
--]]
-- ('a'):byte():char() == 'a'
number.char=string.char
-- me getting tired of typing 'tostring(16)' etc ...
functionnumber.bin(x, ...) returnnumber.tostring(x, 2, ...) end
functionnumber.oct(x, ...) returnnumber.tostring(x, 8, ...) end
functionnumber.hex(x, ...) returnnumber.tostring(x, 16, ...) end
-- so the lookup goes: primitive number -> number -> math
returnnumber