Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create and populate the Maths directory #4

Merged
merged 24 commits into from
Jun 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
* [Catalan Numbers](dynamic_programming/catalan_numbers.nim)
* [Viterbi](dynamic_programming/viterbi.nim)

## Maths
* [Absolute value](maths/abs.nim)
* [Aliquot sum](maths/aliquot_sum.nim)
* [Bitwise Addition](maths/bitwise_addition.nim)

## Strings
* [Check Anagram](strings/check_anagram.nim)

Expand Down
120 changes: 120 additions & 0 deletions maths/abs.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
## Absolute value
{.push raises: [].}
import std/strutils

runnableExamples:
assert absVal(-5.1) == 5.1
assert absMin(@[-1, 2, -3]) == 1
assert absMax(@[-1, 2, -3]) == 3
assert signedMinAbs(@[3, -10, -2]) == -2
assert signedMaxAbs(@[3, -10, -2]) == -10

func absVal*[T: SomeFloat](num: T): T =
## Returns the absolute value of a number.
## Use `math.abs <https://nim-lang.org/docs/system.html#abs%2CT>`_ instead!
return if num < 0.0: -num else: num

# Same for Integers but returns a Natural
func absVal*[T: SomeInteger](num: T): Natural = (if num < 0: -num else: num)

func absMin*(x: openArray[int]): Natural {.raises: [ValueError].} =
## Returns the smallest element in absolute value in a sequence.
if x.len == 0:
raise newException(ValueError, """Cannot find absolute minimum
of an empty sequence""".unindent)
result = absVal(x[0])
for i in 1 ..< x.len:
if absVal(x[i]) < result:
result = absVal(x[i])

func absMax*(x: openArray[int]): Natural {.raises: [ValueError].} =
## Returns the largest element in absolute value in a sequence.
if x.len == 0:
raise newException(ValueError, """Cannot find absolute maximum of an empty
sequence""".unindent)
result = absVal(x[0])
for i in 1 ..< x.len:
if absVal(x[i]) > result:
result = absVal(x[i])

func signedMinAbs*(x: openArray[int]): int {.raises: [ValueError].} =
## Returns the first signed element whose absolute value
## is the smallest in a sequence.
if x.len == 0:
raise newException(ValueError, """Cannot find absolute maximum of an empty
sequence""".unindent)
var (min, minAbs) = (x[0], absVal(x[0]))
for n in x:
let nAbs = absVal(n)
if nAbs < minAbs: (min, minAbs) = (n, nAbs)
min

func signedMaxAbs*(x: openArray[int]): int {.raises: [ValueError].} =
## Returns the first signed element whose absolute value
## is the largest in a sequence.
if x.len == 0:
raise newException(ValueError, """Cannot find absolute maximum of an empty
sequence""".unindent)
var (max, maxAbs) = (x[0], absVal(x[0]))
for n in x:
let nAbs = absVal(n)
if nAbs > maxAbs: (max, maxAbs) = (n, nAbs)
max

when isMainModule:
import std/[unittest, random]
randomize()

suite "Check absVal":
test "Check absVal":
check:
absVal(11.2) == 11.2
absVal(5) == 5
absVal(-5.1) == 5.1
absVal(-5) == absVal(5)
absVal(0) == 0

suite "Check absMin":
test "Check absMin":
check:
absMin(@[-1, 2, -3]) == 1
absMin(@[0, 5, 1, 11]) == 0
absMin(@[3, -10, -2]) == 2
absMin([-1, 2, -3]) == 1
absMin([0, 5, 1, 11]) == 0
absMin([3, -10, -2]) == 2

test "absMin on empty sequence raises ValueError":
doAssertRaises(ValueError):
discard absMin(@[])

suite "Check absMax":
test "Check absMax":
check:
absMax(@[0, 5, 1, 11]) == 11
absMax(@[3, -10, -2]) == 10
absMax(@[-1, 2, -3]) == 3

test "`absMax` on empty sequence raises ValueError":
doAssertRaises(ValueError):
discard absMax(@[])

suite "Check signedMinAbs":
test "Check signedMinAbs":
check:
signedMinAbs(@[0, 5, 1, 11]) == 0
signedMinAbs(@[3, -2, 1, -4, 5, -6]) == 1
signedMinAbs(@[3, -2, -1, -4, 5, -6]) == -1

test "Among two minimal elements, the first one is returned":
check signedMinAbs(@[3, -2, 1, -4, 5, -6, -1]) == 1

suite "Check signedMaxAbs":
test "Check signedMaxAbs":
check:
signedMaxAbs(@[3, -2, 1, -4, 5, -6]) == -6
signedMaxAbs(@[0, 5, 1, 11]) == 11

test "signedMaxAbs on empty sequence raises ValueError":
doAssertRaises(ValueError):
discard signedMaxAbs(@[])
31 changes: 31 additions & 0 deletions maths/aliquot_sum.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
## Aliquot sum
## In number theory, the aliquot sum s(n) of a positive integer n is the sum of
## all proper divisors of n, that is, all divisors of n other than n itself.
## https://en.wikipedia.org/wiki/Aliquot_sum

runnableExamples:
import std/strformat
const expected = [16, 117]
for i, number in [12, 100].pairs():
let sum = aliquotSum(number)
assert sum == expected[i]
echo fmt"The sum of all the proper divisors of {number} is {sum}"

func aliquotSum*(number: Positive): Natural =
## Returns the sum of all the proper divisors of the number
## Example: aliquotSum(12) = 1 + 2 + 3 + 4 + 6 = 16
result = 0
for divisor in 1 .. (number div 2):
if number mod divisor == 0:
result += divisor

when isMainModule:
import std/unittest
suite "Check aliquotSum":
test "aliquotSum on small values":
var
input = @[1, 2, 9, 12, 27, 100]
expected = @[0, 1, 4, 16, 13, 117]
for i in 0 ..< input.len:
check:
aliquotSum(input[i]) == expected[i]
38 changes: 38 additions & 0 deletions maths/bitwise_addition.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
## Bitwise Addition
## Illustrate how to implement addition of integers using bitwise operations
## See https://en.wikipedia.org/wiki/Bitwise_operation#Applications
runnableExamples:
import std/strformat
var
a = 5
b = 6
echo fmt"The sum of {a} and {b} is {add(a,b)}"

func add*(first: int, second: int): int =
## Implementation of addition of integer with `and`, `xor` and `shl`
## boolean operators.
var first = first
var second = second
while second != 0:
var c = first and second
first = first xor second
second = c shl 1
return first

when isMainModule:
import std/unittest

suite "Check addition":
test "Addition of two positive numbers":
check:
add(3, 5) == 8
add(13, 5) == 18
test "Addition of two negative numbers":
check:
add(-7, -2) == -9
add(-321, -0) == -321
test "Addition of one positive and one negative number":
check:
add(-7, 2) == -5
add(-13, 5) == -8
add(13, -5) == 8
Loading