Merge: Added contributing guidelines and link from readme
[nit.git] / lib / core / math.nit
index 50b36e9..7b51e2a 100644 (file)
@@ -67,12 +67,12 @@ redef class Int
        # Returns the result of a binary AND operation on `self` and `i`
        #
        #     assert 0x10 & 0x01 == 0
-       fun &(i: Int): Int `{ return self & i; `}
+       fun &(i: Int): Int is intern `{ return self & i; `}
 
        # Returns the result of a binary OR operation on `self` and `i`
        #
        #     assert 0x10 | 0x01 == 0x11
-       fun |(i: Int): Int `{ return self | i; `}
+       fun |(i: Int): Int is intern `{ return self | i; `}
 
        # Returns the result of a binary XOR operation on `self` and `i`
        #
@@ -128,7 +128,7 @@ redef class Int
        #
        # assert 3.is_prime
        # assert not 1.is_prime
-       # assert not 12.is_prime
+       # assert not 15.is_prime
        fun is_prime: Bool
        do
                if self == 2 then
@@ -136,7 +136,7 @@ redef class Int
                else if self <= 1 or self.is_even then
                        return false
                end
-               for i in [3..self.sqrt[ do
+               for i in [3..self.sqrt] do
                        if self % i == 0 then return false
                end
                return true
@@ -169,13 +169,23 @@ redef class Int
                end
                return res
        end
+
+       # Is `self` a power of two ?
+       #
+       # ~~~nit
+       # assert not 3.is_pow2
+       # assert 2.is_pow2
+       # assert 1.is_pow2
+       # assert not 0.is_pow2
+       # ~~~
+       fun is_pow2: Bool do return self != 0 and (self & self - 1) == 0
 end
 
 redef class Byte
        # Returns the result of a binary AND operation on `self` and `i`
        #
        #     assert 0x10u8 & 0x01u8 == 0u8
-       fun &(i: Byte): Byte `{ return self & i; `}
+       fun &(i: Byte): Byte is intern `{ return self & i; `}
 
        # Returns the result of a binary OR operation on `self` and `i`
        #
@@ -333,6 +343,45 @@ redef class Float
        # assert -0.5.lerp(0.0, 128.0) == -64.0
        # ~~~
        fun lerp(a, b: Float): Float do return (1.0 - self) * a + self * b
+
+       # Quadratic Bézier interpolation between `a` and `b` with an `handle` using `self` as weight
+       #
+       # ~~~
+       # assert  0.00.qerp(0.0, 32.0, 128.0) == 0.0
+       # assert  0.25.qerp(0.0, 32.0, 128.0) == 20.0
+       # assert  0.50.qerp(0.0, 32.0, 128.0) == 48.0
+       # assert  0.75.qerp(0.0, 32.0, 128.0) == 84.0
+       # assert  1.00.qerp(0.0, 32.0, 128.0) == 128.0
+       # ~~~
+       fun qerp(a, handle, b: Float): Float do
+               var p = self
+               var i = 1.0 - p
+               var r =     i*i * a +
+                       2.0*i*p * handle +
+                           p*p * b
+               return r
+       end
+
+       # Cubic Bézier interpolation between `a` and `b` with two handles using `self` as weight
+       #
+       # The Cubic Bézier interpolation is the most common one and use two control points.
+       #
+       # ~~~
+       # assert  0.00.cerp(0.0, 32.0, 128.0, 64.0) == 0.0
+       # assert  0.25.cerp(0.0, 32.0, 128.0, 64.0) == 32.5
+       # assert  0.50.cerp(0.0, 32.0, 128.0, 64.0) == 68.0
+       # assert  0.75.cerp(0.0, 32.0, 128.0, 64.0) == 85.5
+       # assert  1.00.cerp(0.0, 32.0, 128.0, 64.0) == 64.0
+       # ~~~
+       fun cerp(a, a_handle, b_handle, b: Float): Float do
+               var p = self
+               var i = 1.0 - p
+               var r =     i*i*i  * a +
+                       3.0*i*i*p * a_handle +
+                       3.0*i*p*p * b_handle +
+                           p*p*p * b
+               return r
+       end
 end
 
 # Positive float infinite (IEEE 754)
@@ -403,6 +452,40 @@ redef class Collection[ E ]
                res.shuffle
                return res
        end
+
+       # Return a new array made of (at most) `length` elements randomly chosen.
+       #
+       # ~~~
+       # var a = [1,2,1].sample(2)
+       # assert a == [1,1] or a == [1,2] or a == [2,1]
+       # ~~~
+       #
+       # If there is not enough elements, then the result only contains them in a random order.
+       # See `to_shuffle`.
+       #
+       # ENSURE `result.length == self.length.min(length)`
+       #
+       # Note: the default implementation uses the Reservoir Algorithm
+       fun sample(length: Int): Array[E]
+       do
+               if length >= self.length then return to_shuffle
+
+               var res = new Array[E].with_capacity(length)
+               var it = iterator
+               for i in [0..length[ do
+                       res[i] = it.item
+                       it.next
+               end
+               res.shuffle
+               for i in [length+1..self.length] do
+                       var j = i.rand
+                       if j < length then
+                               res[j] = it.item
+                       end
+                       it.next
+               end
+               return res
+       end
 end
 
 redef class SequenceRead[E]
@@ -451,11 +534,11 @@ redef class Sys
        end
 end
 
-# Computes the arc tangent given `x` and `y`.
+# Computes the arc tangent given `y` and `x`.
 #
 #     assert atan2(-0.0, 1.0) == -0.0
 #     assert atan2(0.0, 1.0) == 0.0
-fun atan2(x: Float, y: Float): Float `{ return atan2(x, y); `}
+fun atan2(y: Float, x: Float): Float `{ return atan2(y, x); `}
 
 # Approximate value of **pi**.
 fun pi: Float do return 3.14159265
@@ -472,9 +555,9 @@ fun pi: Float do return 3.14159265
 # assert 10.rand == a
 # assert 100.rand == b
 # ~~~~
-fun srand_from(x: Int) `{ nit_rand_seeded = 1; nit_rand_seed = x; `}
+fun srand_from(x: Int) `{ nit_rand_seeded = 1; nit_rand_seed = (unsigned int)x; `}
 
 # Reinitialize the pseudo-random generator used by the method `rand` and other.
 # This method is automatically invoked at the begin of the program, so usually, there is no need to manually invoke it.
 # The only exception is in conjunction with `srand_from` to reset the pseudo-random generator.
-fun srand `{ nit_rand_seeded = 0; srand(time(NULL)); `}
+fun srand `{ nit_rand_seeded = 0; srand((unsigned int)time(NULL)); `}