Skip to content

Commit 51a2799

Browse files
committed
feat(math): add more bit operations, base conversion, circular bit shifting
1 parent 5958bac commit 51a2799

2 files changed

Lines changed: 182 additions & 2 deletions

File tree

‎Math.ark‎

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,153 @@
239239
# @require 4.6.0 Requires ArkScript 4.6.0 or later
240240
(let rshift (fun (_a _b) (builtin__math:rshift _a _b)))
241241

242+
# @brief Finds the smallest integral power of 2 not less than the given value
243+
# @param value Number, must be an integer
244+
# =begin
245+
# (math:bitCeil 4) # 4
246+
# (math:bitCeil 7) # 8
247+
# (math:bitCeil 8) # 8
248+
# =end
249+
# @author https://github.com/SuperFola
250+
# @require 4.6.0 Requires ArkScript 4.6.0 or later
251+
(let bitCeil (fun (_x) (builtin__math:bitCeil _x)))
252+
253+
# @brief Finds the largest integral power of 2 not greater than the given value
254+
# @param value Number, must be an integer
255+
# =begin
256+
# (math:bitFloor 4) # 4
257+
# (math:bitFloor 7) # 4
258+
# (math:bitFloor 8) # 8
259+
# =end
260+
# @author https://github.com/SuperFola
261+
# @require 4.6.0 Requires ArkScript 4.6.0 or later
262+
(let bitFloor (fun (_x) (builtin__math:bitFloor _x)))
263+
264+
# @brief Finds the smallest number of bits needed to represent the given value
265+
# @param value Number, must be an integer
266+
# =begin
267+
# (math:bitWidth 2) # 2
268+
# (math:bitWidth 7) # 3
269+
# (math:bitWidth 8) # 4
270+
# =end
271+
# @author https://github.com/SuperFola
272+
# @require 4.6.0 Requires ArkScript 4.6.0 or later
273+
(let bitWidth (fun (_x) (builtin__math:bitWidth _x)))
274+
275+
# @brief Counts the number of consecutive 0 bits, starting from the most significant bit
276+
# @param n Number, must be an integer
277+
# @param bits Number of bits to represent n in, must be an integer
278+
# =begin
279+
# (math:countLeftZeros 30 8) # 3
280+
# (math:countLeftZeros 227 8) # 0
281+
# =end
282+
# @author https://github.com/SuperFola
283+
# @require 4.6.0 Requires ArkScript 4.6.0 or later
284+
(let countLeftZeros (fun (_n _bits) (builtin__math:countLeftZeros _n _bits)))
285+
286+
# @brief Counts the number of consecutive 1 bits, starting from the most significant bit
287+
# @param n Number, must be an integer
288+
# @param bits Number of bits to represent n in, must be an integer
289+
# =begin
290+
# (math:countLeftOnes 30 8) # 4
291+
# (math:countLeftOnes 227 8) # 3
292+
# =end
293+
# @author https://github.com/SuperFola
294+
# @require 4.6.0 Requires ArkScript 4.6.0 or later
295+
(let countLeftOnes (fun (_n _bits) (builtin__math:countLeftOnes _n _bits)))
296+
297+
# @brief Counts the number of consecutive 0 bits, starting from the least significant bit
298+
# @param n Number, must be an integer
299+
# @param bits Number of bits to represent n in, must be an integer
300+
# =begin
301+
# (math:countRightZeros 30 8) # 1
302+
# (math:countRightZeros 227 8) # 0
303+
# =end
304+
# @author https://github.com/SuperFola
305+
# @require 4.6.0 Requires ArkScript 4.6.0 or later
306+
(let countRightZeros (fun (_n _bits) (builtin__math:countRightZeros _n _bits)))
307+
308+
# @brief Counts the number of consecutive 1 bits, starting from the least significant bit
309+
# @param n Number, must be an integer
310+
# @param bits Number of bits to represent n in, must be an integer
311+
# =begin
312+
# (math:countRightOnes 30 8) # 0
313+
# (math:countRightOnes 227 8) # 2
314+
# =end
315+
# @author https://github.com/SuperFola
316+
# @require 4.6.0 Requires ArkScript 4.6.0 or later
317+
(let countRightOnes (fun (_n _bits) (builtin__math:countRightOnes _n _bits)))
318+
319+
# @brief Computes the result of bitwise left-rotation of _x by _count
320+
# @param _x Number, must be an integer
321+
# @param _count Number, must be an integer
322+
# @param _bytecount Number of bytes to shift on, must be an integer
323+
# =begin
324+
# (math:circularLeftShift 29 4 1) # 209
325+
# (math:circularLeftShift 29 9 1) # 58
326+
# =end
327+
# @author https://github.com/SuperFola
328+
# @require 4.6.0 Requires ArkScript 4.6.0 or later
329+
(let circularLeftShift (fun (_x (mut _count) _bytecount) {
330+
(assert (and (>= _bytecount 1) (<= _bytecount 8)) "bytecount must be in [1, 8]")
331+
(let _max (- (* 8 _bytecount) 1))
332+
(let _mask (- (lshift 1 (* 8 _bytecount)) 1))
333+
(set _count (bitAnd _count _max))
334+
(bitAnd (bitOr (lshift _x _count) (rshift _x (bitAnd (* -1 _count) _max))) _mask) }))
335+
336+
# @brief Computes the result of bitwise left-rotation of _x by _count
337+
# @param _x Number, must be an integer
338+
# @param _count Number, must be an integer
339+
# @param _bytecount Number of bytes to shift on, must be an integer
340+
# =begin
341+
# (math:circularRightShift 29 9 1) # 142
342+
# (math:circularRightShift 29 2 1) # 71
343+
# =end
344+
# @author https://github.com/SuperFola
345+
# @require 4.6.0 Requires ArkScript 4.6.0 or later
346+
(let circularRightShift (fun (_x (mut _count) _bytecount) {
347+
(assert (and (>= _bytecount 1) (<= _bytecount 8)) "bytecount must be in [1, 8]")
348+
(let _max (- (* 8 _bytecount) 1))
349+
(let _mask (- (lshift 1 (* 8 _bytecount)) 1))
350+
(set _count (bitAnd _count _max))
351+
(bitAnd (bitOr (rshift _x _count) (lshift _x (bitAnd (* -1 _count) _max))) _mask) }))
352+
353+
(let _base_conversion_alphabet "0123456789abcdefghijklmnopqrstuvwxyz")
354+
355+
# @brief Convert a number in a another base (in [2, 36[)
356+
# @param _x Number, must be an integer
357+
# @param _base Number, must be an integer
358+
# =begin
359+
# (math:toBase 10 2) # "1010"
360+
# (math:toBase 165 16) # "a5"
361+
# =end
362+
# @author https://github.com/SuperFola
363+
# @require 4.6.0 Requires ArkScript 4.6.0 or later
364+
(let toBase (fun ((mut _x) _base) {
365+
(assert (and (> _base 1) (< _base 36)) "Base must be in [2, 36[")
366+
(mut _out "")
367+
(while _x {
368+
(set _out (+ (@ _base_conversion_alphabet (mod _x _base)) _out))
369+
(set _x (floordiv _x _base)) })
370+
_out }))
371+
372+
# @brief Count the digits of a number in a given base (in [2, 36[)
373+
# @param _x Number, must be an integer
374+
# @param _base Number, must be an integer
375+
# =begin
376+
# (math:countDigits 10 2) # 4
377+
# (math:countDigits 165 16) # 2
378+
# =end
379+
# @author https://github.com/SuperFola
380+
# @require 4.6.0 Requires ArkScript 4.6.0 or later
381+
(let countDigits (fun ((mut _x) _base) {
382+
(assert (and (> _base 1) (< _base 36)) "Base must be in [2, 36[")
383+
(mut _out 0)
384+
(while _x {
385+
(set _out (+ 1 _out))
386+
(set _x (floordiv _x _base)) })
387+
_out }))
388+
242389
# @brief Return the absolute value of a number
243390
# @param _x the number to get the absolute value of
244391
# @author https://github.com/rstefanic

‎tests/math-tests.ark‎

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,14 @@
3737
(test:eq (builtin__math:bitOr 1234 5678) (math:bitOr 1234 5678))
3838
(test:eq (builtin__math:bitXor 1234 5678) (math:bitXor 1234 5678))
3939
(test:eq (builtin__math:lshift 1234 2) (math:lshift 1234 2))
40-
(test:eq (builtin__math:rshift 1234 6) (math:rshift 1234 6)) })
40+
(test:eq (builtin__math:rshift 1234 6) (math:rshift 1234 6))
41+
(test:eq (builtin__math:bitCeil 1234) (math:bitCeil 1234))
42+
(test:eq (builtin__math:bitFloor 1234) (math:bitFloor 1234))
43+
(test:eq (builtin__math:bitWidth 1234) (math:bitWidth 1234))
44+
(test:eq (builtin__math:countLeftZeros 1234 32) (math:countLeftZeros 1234 32))
45+
(test:eq (builtin__math:countLeftOnes 1234 32) (math:countLeftOnes 1234 32))
46+
(test:eq (builtin__math:countRightZeros 1234 32) (math:countRightZeros 1234 32))
47+
(test:eq (builtin__math:countRightOnes 1234 32) (math:countRightOnes 1234 32)) })
4148

4249
(test:case "bitwise" {
4350
(test:eq (math:countOnes 5) 2)
@@ -54,7 +61,33 @@
5461
(test:eq (math:bitXor 4 10) 14)
5562
(test:eq (math:lshift 3 2) 12)
5663
(test:eq (math:rshift 13 2) 3)
57-
(test:eq (math:rshift -14 2) -4) })
64+
(test:eq (math:rshift -14 2) -4)
65+
66+
(test:eq (math:countLeftZeros 30 8) 3)
67+
(test:eq (math:countLeftZeros 227 8) 0)
68+
(test:eq (math:countLeftOnes 30 5) 4)
69+
(test:eq (math:countLeftOnes 30 8) 0)
70+
(test:eq (math:countLeftOnes 227 8) 3)
71+
(test:eq (math:countRightZeros 30 8) 1)
72+
(test:eq (math:countRightZeros 227 8) 0)
73+
(test:eq (math:countRightOnes 30 8) 0)
74+
(test:eq (math:countRightOnes 227 8) 2)
75+
76+
(test:eq (math:circularLeftShift 29 4 1) 209)
77+
(test:eq (math:circularLeftShift 29 9 1) 58)
78+
(test:eq (math:circularRightShift 29 9 1) 142)
79+
(test:eq (math:circularRightShift 29 2 1) 71) })
80+
81+
(test:case "toBase" {
82+
(test:eq (math:toBase 10 10) "10")
83+
(test:eq (math:toBase 10 16) "a")
84+
(test:eq (math:toBase 10 2) "1010")
85+
(test:eq (math:toBase 165 16) "a5") })
86+
87+
(test:case "countDigits" {
88+
(test:eq (math:countDigits 10 2) 4)
89+
(test:eq (math:countDigits 10 10) 2)
90+
(test:eq (math:countDigits 165 16) 2) })
5891

5992
(test:case "abs" {
6093
(test:eq (math:abs -1) 1)

0 commit comments

Comments
 (0)