Skip to content

Commit 571a578

Browse files
committed
Add a sample of maths basic algorithms
1 parent 7123571 commit 571a578

File tree

4 files changed

+206
-0
lines changed

4 files changed

+206
-0
lines changed

maths/abs.nim

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
## Absolute value
2+
{.push raises: [].}
3+
import std/algorithm
4+
5+
runnableExamples:
6+
doAssert absVal(-5.1) == 5.1
7+
doAssert absMin(@[-1, 2, -3]) == 1
8+
doAssert absMax(@[-1, 2, -3]) == 3
9+
doAssert absMaxSort(@[3, -10, -2]) == -10
10+
11+
func absVal(num: float): float =
12+
## Returns the absolute value of a number.
13+
return if num < 0.0: -num else: num
14+
15+
# Same for integers but return a Natural
16+
func absVal(num: int): Natural = (if num < 0: -num else: num)
17+
18+
func absMin(x: seq[int]): Natural {.raises: [ValueError].} =
19+
## Returns the smallest element in absolute value in a sequence.
20+
if x.len == 0:
21+
raise newException(ValueError, "Cannot find absolute minimum of an empty sequence")
22+
result = absVal(x[0])
23+
for i in 1 ..< x.len:
24+
if absVal(x[i]) < result:
25+
result = absVal(x[i])
26+
27+
func absMax(x: seq[int]): Natural {.raises: [ValueError].} =
28+
## Returns the largest element in absolute value in a sequence.
29+
if x.len == 0:
30+
raise newException(ValueError, "Cannot find absolute maximum of an empty sequence")
31+
result = absVal(x[0])
32+
for i in 1 ..< x.len:
33+
if absVal(x[i]) > result:
34+
result = absVal(x[i])
35+
36+
func absMaxSort(x: seq[int]): int {.raises: [ValueError].} =
37+
## Returns the signed element whose absolute value is the largest in a sequence.
38+
var x: seq[int] = x
39+
if x.len == 0:
40+
raise newException(ValueError, "Cannot find absolute maximum of an empty sequence")
41+
sort(x, proc (a, b: int): int = int(absVal(b)) - int(absVal(a)))
42+
return x[0]
43+
44+
when isMainModule:
45+
import std/[unittest, random]
46+
randomize()
47+
48+
suite "Check `absVal`":
49+
test "Check `absVal`":
50+
check:
51+
absVal(11.2) == 11.2
52+
absVal(5) == 5
53+
absVal(-5.1) == 5.1
54+
absVal(-5) == abs_val(5)
55+
absVal(0) == 0
56+
57+
suite "Check `absMin`":
58+
test "Check `absMin`":
59+
check:
60+
absMin(@[-1, 2, -3]) == 1
61+
absMin(@[0, 5, 1, 11]) == 0
62+
absMin(@[3, -10, -2]) == 2
63+
64+
test "`absMin` on empty sequence raises ValueError":
65+
doAssertRaises(ValueError):
66+
discard absMin(@[])
67+
68+
suite "Check `absMax`":
69+
test "Check `absMax`":
70+
check:
71+
absMax(@[0, 5, 1, 11]) == 11
72+
absMax(@[3, -10, -2]) == 10
73+
absMax(@[-1, 2, -3]) == 3
74+
75+
test "`absMax` on empty sequence raises ValueError":
76+
doAssertRaises(ValueError):
77+
discard absMax(@[])
78+
79+
suite "Check `absMaxSort`":
80+
test "Check `absMaxSort`":
81+
check:
82+
absMaxSort(@[3, -2, 1, -4, 5, -6]) == -6
83+
absMaxSort(@[0, 5, 1, 11]) == 11
84+
85+
test "`absMaxSort` on empty sequence raises ValueError":
86+
doAssertRaises(ValueError):
87+
discard absMaxSort(@[])

maths/addition_without_arithmetic.nim

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
## Illustrate how to add the integer without arithmetic operation
2+
runnableExamples:
3+
import std/strformat
4+
var
5+
a = 5
6+
b = 6
7+
echo fmt"The sum of {a} and {b} is {add(a,b)}"
8+
9+
func add(first: int, second: int): int =
10+
## Implementation of addition of integer with `and`, `xor` and `shl`
11+
## boolean operators.
12+
var first = first
13+
var second = second
14+
while second != 0:
15+
var c = first and second
16+
first = first xor second
17+
second = c shl 1
18+
return first
19+
20+
when isMainModule:
21+
import std/unittest
22+
23+
suite "Check addition":
24+
test "Addition of two positive numbers":
25+
check:
26+
add(3, 5) == 8
27+
add(13, 5) == 18
28+
test "Addition of two negative numbers":
29+
check:
30+
add(-7, -2) == -9
31+
add(-321, -0) == -321
32+
test "Addition of one positive and one negative number":
33+
check:
34+
add(-7, 2) == -5
35+
add(-13, 5) == -8
36+
add(13, -5) == 8

maths/aliquot_sum.nim

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{.push raises: [].}
2+
3+
runnableExamples:
4+
import std/strformat
5+
for number in [12, 100]:
6+
echo fmt"The sum of all the proper divisors of {number} is {aliquotSum(number)}"
7+
8+
func aliquotSum(number: Natural): Natural {.raises: [ValueError].} =
9+
## Returns the sum of all the proper divisors of the number
10+
## Example: aliquotSum(12) = 1 + 2 + 3 + 4 + 6 = 16
11+
if number == 0:
12+
raise newException(ValueError, "Input number must be strictly positive")
13+
result = 0
14+
for divisor in 1 .. (number div 2) :
15+
if number mod divisor == 0:
16+
result += divisor
17+
18+
when isMainModule:
19+
import std/unittest
20+
suite "Check `aliquotSum`":
21+
test "`aliquotSum` on small values":
22+
var
23+
input = @[1, 2, 9, 12, 27, 100]
24+
expected = @[0, 1, 4, 16, 13, 117]
25+
for i in 0 ..< input.len:
26+
check:
27+
aliquotSum(input[i]) == expected[i]
28+
29+
test "`aliquotSum` raises ValueError on non-positive entries":
30+
doAssertRaises(ValueError):
31+
discard aliquotSum(0)

maths/allocation_number.nim

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
## In a multi-threaded download, this algorithmm could be used to provide
2+
## each worker thread with a block of non-overlapping bytes to download.
3+
4+
runnableExamples:
5+
let numBytes = 100
6+
let numPartitions = 5
7+
let allocations = allocationNum(numBytes, numPartitions)
8+
doAssert allocations == @[
9+
0 .. 19,
10+
20 .. 39,
11+
40 .. 59,
12+
60 .. 79,
13+
80 .. 100
14+
]
15+
16+
func allocationNum(numBytes: Natural, numPartitions: Natural): seq[Slice[Natural]] =
17+
## Divide `numBytes` bytes into `numPartitions` non-overlapping partitions.
18+
if numPartitions <= 0:
19+
raise newException(ValueError, "numPartitions must be > 0")
20+
if numPartitions > numBytes:
21+
raise newException(ValueError, "numPartitions must be <= numBytes")
22+
var
23+
bytesPerPartition = numBytes div numPartitions
24+
allocation_list: seq[Slice[Natural]] = @[]
25+
for i in Natural(0) ..< numPartitions:
26+
if i == numPartitions-1:
27+
allocation_list.add(Natural(i*bytesPerPartition) .. numBytes)
28+
else:
29+
allocation_list.add(Natural(i*bytesPerPartition) .. Natural((i+1)*bytesPerPartition-1))
30+
return allocation_list
31+
32+
when isMainModule:
33+
import std/unittest
34+
35+
suite "Test `allocationNum`":
36+
test "Test `allocationNum`":
37+
let allocations: seq[Slice[Natural]] = allocationNum(100, 5)
38+
check allocations == @[
39+
Natural(0) .. 19,
40+
Natural(20) .. 39,
41+
Natural(40) .. 59,
42+
Natural(60) .. 79,
43+
Natural(80) .. 100
44+
]
45+
46+
test "`allocationNum` on 0 partitions":
47+
doAssertRaises(ValueError): discard allocationNum(5, 0)
48+
49+
test "`allocationNum` on more partitions than bytes":
50+
doAssertRaises(ValueError): discard allocationNum(0, 5)
51+
52+
echo allocationNum(0, 5)

0 commit comments

Comments
 (0)