diff --git a/api/integers.md b/api/integers.md index acbab60..653322f 100644 --- a/api/integers.md +++ b/api/integers.md @@ -302,7 +302,8 @@ The next prime number greater than `x`. **Example:** ```tomo -11:next_prime() // 13 +>> 11:next_prime() += 13 ``` --- @@ -334,5 +335,34 @@ The previous prime number less than `x`. **Example:** ```tomo -11:prev_prime() // 7 +>> 11:prev_prime() += 7 +``` + +--- + +## `clamped` + +**Description:** +Returns the given number clamped between two values so that it is within +that range. + +**Usage:** +```tomo +clamped(x, low, high: Int) -> Int +``` + +**Parameters:** + +- `x`: The integer to clamp. +- `low`: The lowest value the result can take. +- `high`: The highest value the result can take. + +**Returns:** +The first argument clamped between the other two arguments. + +**Example:** +```tomo +>> 2:clamped(5, 10) += 5 ``` diff --git a/api/nums.md b/api/nums.md index 5f28b1a..5b25801 100644 --- a/api/nums.md +++ b/api/nums.md @@ -1344,3 +1344,31 @@ The Bessel function of the second kind of order 1 of `x`. >> 1.0:y1() = 0.4401 ``` + +--- + +## `clamped` + +**Description:** +Returns the given number clamped between two values so that it is within +that range. + +**Usage:** +```tomo +clamped(x, low, high: Num) -> Num +``` + +**Parameters:** + +- `x`: The number to clamp. +- `low`: The lowest value the result can take. +- `high`: The highest value the result can take. + +**Returns:** +The first argument clamped between the other two arguments. + +**Example:** +```tomo +>> 2.5:clamped(5.5, 10.5) += 5.5 +``` diff --git a/builtins/integers.h b/builtins/integers.h index ed3e293..b4cb211 100644 --- a/builtins/integers.h +++ b/builtins/integers.h @@ -34,6 +34,9 @@ c_type type_name ## $random(c_type min, c_type max); \ Range_t type_name ## $to(c_type from, c_type to); \ c_type type_name ## $from_text(CORD text, CORD *the_rest); \ + static inline c_type type_name ## $clamped(c_type x, c_type min, c_type max) { \ + return x < min ? min : (x > max ? max : x); \ + } \ extern const c_type type_name ## $min, type_name##$max; \ extern const TypeInfo $ ## type_name; \ static inline c_type type_name ## $divided_by(c_type D, c_type d) { \ @@ -123,6 +126,11 @@ Int_t Int$prev_prime(Int_t x); extern const TypeInfo $Int; +static inline Int_t Int$clamped(Int_t x, Int_t low, Int_t high) +{ + return (Int$compare(&x, &low, &$Int) <= 0) ? low : (Int$compare(&x, &high, &$Int) >= 0 ? high : x); +} + // Fast-path inline versions for the common case where integer arithmetic is // between two small ints. diff --git a/builtins/nums.h b/builtins/nums.h index d08dcc4..94b1105 100644 --- a/builtins/nums.h +++ b/builtins/nums.h @@ -28,6 +28,9 @@ double Num$nan(CORD tag); double Num$random(void); double Num$mix(double amount, double x, double y); double Num$from_text(CORD text, CORD *the_rest); +static inline double Num$clamped(double x, double low, double high) { + return (x <= low) ? low : (x >= high ? high : x); +} extern const TypeInfo $Num; CORD Num32$as_text(const float *f, bool colorize, const TypeInfo *type); @@ -44,6 +47,9 @@ float Num32$random(void); float Num32$mix(float amount, float x, float y); float Num32$from_text(CORD text, CORD *the_rest); float Num32$nan(CORD tag); +static inline float Num32$clamped(float x, float low, float high) { + return (x <= low) ? low : (x >= high ? high : x); +} extern const TypeInfo $Num32; // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/environment.c b/environment.c index 805b184..a54cf5d 100644 --- a/environment.c +++ b/environment.c @@ -88,97 +88,103 @@ env_t *new_compilation_unit(CORD *libname) {"random", "Bool$random", "func(p=0.5)->Bool"}, )}, {"Int", Type(BigIntType), "Int_t", "$Int", TypedArray(ns_entry_t, - {"format", "Int$format", "func(i:Int, digits=0)->Text"}, - {"hex", "Int$hex", "func(i:Int, digits=0, uppercase=yes, prefix=yes)->Text"}, - {"octal", "Int$octal", "func(i:Int, digits=0, prefix=yes)->Text"}, - {"random", "Int$random", "func(min:Int, max:Int)->Int"}, - {"from_text", "Int$from_text", "func(text:Text, the_rest=!&Text)->Int"}, - {"to", "Int$to", "func(from:Int,to:Int)->Range"}, - {"plus", "Int$plus", "func(x:Int,y:Int)->Int"}, - {"minus", "Int$minus", "func(x:Int,y:Int)->Int"}, - {"times", "Int$times", "func(x:Int,y:Int)->Int"}, - {"divided_by", "Int$divided_by", "func(x:Int,y:Int)->Int"}, - {"modulo", "Int$modulo", "func(x:Int,y:Int)->Int"}, - {"modulo1", "Int$modulo1", "func(x:Int,y:Int)->Int"}, - {"left_shifted", "Int$left_shifted", "func(x:Int,y:Int)->Int"}, - {"right_shifted", "Int$right_shifted", "func(x:Int,y:Int)->Int"}, + {"abs", "Int$abs", "func(x:Int)->Int"}, {"bit_and", "Int$bit_and", "func(x:Int,y:Int)->Int"}, {"bit_or", "Int$bit_or", "func(x:Int,y:Int)->Int"}, {"bit_xor", "Int$bit_xor", "func(x:Int,y:Int)->Int"}, - {"negative", "Int$negative", "func(x:Int)->Int"}, - {"negated", "Int$negated", "func(x:Int)->Int"}, - {"abs", "Int$abs", "func(x:Int)->Int"}, - {"sqrt", "Int$sqrt", "func(x:Int)->Int"}, - {"power", "Int$power", "func(base:Int,exponent:Int)->Int"}, + {"clamped", "Int$clamped", "func(x:Int,low:Int,high:Int)->Int"}, + {"divided_by", "Int$divided_by", "func(x:Int,y:Int)->Int"}, + {"format", "Int$format", "func(i:Int, digits=0)->Text"}, + {"from_text", "Int$from_text", "func(text:Text, the_rest=!&Text)->Int"}, + {"hex", "Int$hex", "func(i:Int, digits=0, uppercase=yes, prefix=yes)->Text"}, {"is_prime", "Int$is_prime", "func(x:Int,reps=50)->Bool"}, + {"left_shifted", "Int$left_shifted", "func(x:Int,y:Int)->Int"}, + {"minus", "Int$minus", "func(x:Int,y:Int)->Int"}, + {"modulo", "Int$modulo", "func(x:Int,y:Int)->Int"}, + {"modulo1", "Int$modulo1", "func(x:Int,y:Int)->Int"}, + {"negated", "Int$negated", "func(x:Int)->Int"}, + {"negative", "Int$negative", "func(x:Int)->Int"}, {"next_prime", "Int$next_prime", "func(x:Int)->Int"}, + {"octal", "Int$octal", "func(i:Int, digits=0, prefix=yes)->Text"}, + {"plus", "Int$plus", "func(x:Int,y:Int)->Int"}, + {"power", "Int$power", "func(base:Int,exponent:Int)->Int"}, {"prev_prime", "Int$prev_prime", "func(x:Int)->Int"}, + {"random", "Int$random", "func(min:Int, max:Int)->Int"}, + {"right_shifted", "Int$right_shifted", "func(x:Int,y:Int)->Int"}, + {"sqrt", "Int$sqrt", "func(x:Int)->Int"}, + {"times", "Int$times", "func(x:Int,y:Int)->Int"}, + {"to", "Int$to", "func(from:Int,to:Int)->Range"}, )}, {"Int64", Type(IntType, .bits=TYPE_IBITS64), "Int64_t", "$Int64", TypedArray(ns_entry_t, - {"format", "Int64$format", "func(i:Int64, digits=0)->Text"}, - {"hex", "Int64$hex", "func(i:Int64, digits=0, uppercase=yes, prefix=yes)->Text"}, - {"octal", "Int64$octal", "func(i:Int64, digits=0, prefix=yes)->Text"}, - {"random", "Int64$random", "func(min=-0x8000000000000000_i64, max=0x7FFFFFFFFFFFFFFF_i64)->Int64"}, - {"from_text", "Int64$from_text", "func(text:Text, the_rest=!&Text)->Int64"}, - {"bits", "Int64$bits", "func(x:Int64)->[Bool]"}, {"abs", "labs", "func(i:Int64)->Int64"}, - {"min", "Int64$min", "Int64"}, - {"max", "Int64$max", "Int64"}, - {"to", "Int64$to", "func(from:Int64,to:Int64)->Range"}, + {"bits", "Int64$bits", "func(x:Int64)->[Bool]"}, + {"clamped", "Int64$clamped", "func(x:Int64,low:Int64,high:Int64)->Int64"}, {"divided_by", "Int64$divided_by", "func(x:Int64,y:Int64)->Int64"}, + {"format", "Int64$format", "func(i:Int64, digits=0)->Text"}, + {"from_text", "Int64$from_text", "func(text:Text, the_rest=!&Text)->Int64"}, + {"hex", "Int64$hex", "func(i:Int64, digits=0, uppercase=yes, prefix=yes)->Text"}, + {"max", "Int64$max", "Int64"}, + {"min", "Int64$min", "Int64"}, {"modulo", "Int64$modulo", "func(x:Int64,y:Int64)->Int64"}, {"modulo1", "Int64$modulo1", "func(x:Int64,y:Int64)->Int64"}, + {"octal", "Int64$octal", "func(i:Int64, digits=0, prefix=yes)->Text"}, + {"random", "Int64$random", "func(min=-0x8000000000000000_i64, max=0x7FFFFFFFFFFFFFFF_i64)->Int64"}, + {"to", "Int64$to", "func(from:Int64,to:Int64)->Range"}, )}, {"Int32", Type(IntType, .bits=TYPE_IBITS32), "Int32_t", "$Int32", TypedArray(ns_entry_t, - {"format", "Int32$format", "func(i:Int32, digits=0)->Text"}, - {"hex", "Int32$hex", "func(i:Int32, digits=0, uppercase=yes, prefix=yes)->Text"}, - {"octal", "Int32$octal", "func(i:Int32, digits=0, prefix=yes)->Text"}, - {"random", "Int32$random", "func(min=-0x80000000_i32, max=0x7FFFFFFF_i32)->Int32"}, - {"from_text", "Int$from_text", "func(text:Text, the_rest=!&Text)->Int32"}, - {"bits", "Int32$bits", "func(x:Int32)->[Bool]"}, {"abs", "abs", "func(i:Int32)->Int32"}, - {"min", "Int32$min", "Int32"}, - {"max", "Int32$max", "Int32"}, - {"to", "Int32$to", "func(from:Int32,to:Int32)->Range"}, + {"bits", "Int32$bits", "func(x:Int32)->[Bool]"}, + {"clamped", "Int32$clamped", "func(x:Int32,low:Int32,high:Int32)->Int32"}, {"divided_by", "Int32$divided_by", "func(x:Int32,y:Int32)->Int32"}, + {"format", "Int32$format", "func(i:Int32, digits=0)->Text"}, + {"from_text", "Int$from_text", "func(text:Text, the_rest=!&Text)->Int32"}, + {"hex", "Int32$hex", "func(i:Int32, digits=0, uppercase=yes, prefix=yes)->Text"}, + {"max", "Int32$max", "Int32"}, + {"min", "Int32$min", "Int32"}, {"modulo", "Int32$modulo", "func(x:Int32,y:Int32)->Int32"}, {"modulo1", "Int32$modulo1", "func(x:Int32,y:Int32)->Int32"}, + {"octal", "Int32$octal", "func(i:Int32, digits=0, prefix=yes)->Text"}, + {"random", "Int32$random", "func(min=-0x80000000_i32, max=0x7FFFFFFF_i32)->Int32"}, + {"to", "Int32$to", "func(from:Int32,to:Int32)->Range"}, )}, {"Int16", Type(IntType, .bits=TYPE_IBITS16), "Int16_t", "$Int16", TypedArray(ns_entry_t, - {"format", "Int16$format", "func(i:Int16, digits=0)->Text"}, - {"hex", "Int16$hex", "func(i:Int16, digits=0, uppercase=yes, prefix=yes)->Text"}, - {"octal", "Int16$octal", "func(i:Int16, digits=0, prefix=yes)->Text"}, - {"random", "Int16$random", "func(min=-0x8000_i16, max=0x7FFF_i16)->Int16"}, - {"from_text", "Int$from_text", "func(text:Text, the_rest=!&Text)->Int16"}, - {"bits", "Int16$bits", "func(x:Int16)->[Bool]"}, {"abs", "abs", "func(i:Int16)->Int16"}, - {"min", "Int16$min", "Int16"}, - {"max", "Int16$max", "Int16"}, - {"to", "Int16$to", "func(from:Int16,to:Int16)->Range"}, + {"bits", "Int16$bits", "func(x:Int16)->[Bool]"}, + {"clamped", "Int16$clamped", "func(x:Int16,low:Int16,high:Int16)->Int16"}, {"divided_by", "Int16$divided_by", "func(x:Int16,y:Int16)->Int16"}, + {"format", "Int16$format", "func(i:Int16, digits=0)->Text"}, + {"from_text", "Int$from_text", "func(text:Text, the_rest=!&Text)->Int16"}, + {"hex", "Int16$hex", "func(i:Int16, digits=0, uppercase=yes, prefix=yes)->Text"}, + {"max", "Int16$max", "Int16"}, + {"min", "Int16$min", "Int16"}, {"modulo", "Int16$modulo", "func(x:Int16,y:Int16)->Int16"}, {"modulo1", "Int16$modulo1", "func(x:Int16,y:Int16)->Int16"}, + {"octal", "Int16$octal", "func(i:Int16, digits=0, prefix=yes)->Text"}, + {"random", "Int16$random", "func(min=-0x8000_i16, max=0x7FFF_i16)->Int16"}, + {"to", "Int16$to", "func(from:Int16,to:Int16)->Range"}, )}, {"Int8", Type(IntType, .bits=TYPE_IBITS8), "Int8_t", "$Int8", TypedArray(ns_entry_t, - {"format", "Int8$format", "func(i:Int8, digits=0)->Text"}, - {"hex", "Int8$hex", "func(i:Int8, digits=0, uppercase=yes, prefix=yes)->Text"}, - {"octal", "Int8$octal", "func(i:Int8, digits=0, prefix=yes)->Text"}, - {"random", "Int8$random", "func(min=-0x80_i8, max=0x7F_i8)->Int8"}, - {"from_text", "Int$from_text", "func(text:Text, the_rest=!&Text)->Int8"}, - {"bits", "Int8$bits", "func(x:Int8)->[Bool]"}, {"abs", "abs", "func(i:Int8)->Int8"}, - {"min", "Int8$min", "Int8"}, - {"max", "Int8$max", "Int8"}, - {"to", "Int8$to", "func(from:Int8,to:Int8)->Range"}, + {"bits", "Int8$bits", "func(x:Int8)->[Bool]"}, + {"clamped", "Int8$clamped", "func(x:Int8,low:Int8,high:Int8)->Int8"}, {"divided_by", "Int8$divided_by", "func(x:Int8,y:Int8)->Int8"}, + {"format", "Int8$format", "func(i:Int8, digits=0)->Text"}, + {"from_text", "Int$from_text", "func(text:Text, the_rest=!&Text)->Int8"}, + {"hex", "Int8$hex", "func(i:Int8, digits=0, uppercase=yes, prefix=yes)->Text"}, + {"max", "Int8$max", "Int8"}, + {"min", "Int8$min", "Int8"}, {"modulo", "Int8$modulo", "func(x:Int8,y:Int8)->Int8"}, {"modulo1", "Int8$modulo1", "func(x:Int8,y:Int8)->Int8"}, + {"octal", "Int8$octal", "func(i:Int8, digits=0, prefix=yes)->Text"}, + {"random", "Int8$random", "func(min=-0x80_i8, max=0x7F_i8)->Int8"}, + {"to", "Int8$to", "func(from:Int8,to:Int8)->Range"}, )}, #define C(name) {#name, "M_"#name, "Num"} #define F(name) {#name, #name, "func(n:Num)->Num"} #define F2(name) {#name, #name, "func(x:Num, y:Num)->Num"} {"Num", Type(NumType, .bits=TYPE_NBITS64), "Num_t", "$Num", TypedArray(ns_entry_t, {"near", "Num$near", "func(x:Num, y:Num, ratio=1e-9, min_epsilon=1e-9)->Bool"}, + {"clamped", "Num$clamped", "func(x:Num,low:Num,high:Num)->Num"}, {"format", "Num$format", "func(n:Num, precision=0)->Text"}, {"scientific", "Num$scientific", "func(n:Num, precision=0)->Text"}, {"nan", "Num$nan", "func(tag=\"\")->Num"}, @@ -207,6 +213,7 @@ env_t *new_compilation_unit(CORD *libname) #define F2(name) {#name, #name"f", "func(x:Num32, y:Num32)->Num32"} {"Num32", Type(NumType, .bits=TYPE_NBITS32), "Num32_t", "$Num32", TypedArray(ns_entry_t, {"near", "Num32$near", "func(x:Num32, y:Num32, ratio=1e-9f32, min_epsilon=1e-9f32)->Bool"}, + {"clamped", "Num32$clamped", "func(x:Num32,low:Num32,high:Num32)->Num32"}, {"format", "Num32$format", "func(n:Num32, precision=0)->Text"}, {"scientific", "Num32$scientific", "func(n:Num32, precision=0)->Text"}, {"nan", "Num32$nan", "func(tag=\"\")->Num32"},