diff --git a/docs/scarpet/language/Operators.md b/docs/scarpet/language/Operators.md index 2be18a7a..cc5b8d0a 100644 --- a/docs/scarpet/language/Operators.md +++ b/docs/scarpet/language/Operators.md @@ -294,4 +294,30 @@ so some caution (prior testing) is advised. Some of these multi-argument built-i `if`, `try`, `sort_key`, `system_variable_get`, `synchronize`, `sleep`, `in_dimension`, all container functions (`get`, `has`, `put`, `delete`), and all loop functions (`while`, `loop`, `map`, `filter`, `first`, `all`, `c_for`, `for` and`reduce`). - + +### `Binary (bitwise) operations` + +These are a bunch of operators that work exclusively on numbers, more specifically their binary representations. Some of these +work on multiple numbers, some on only 2, and others on only 1. Note that most of these functions (all but `double_to_long_bits`) +only take integer values, so if the input has a decimal part, it will be discarded. + + - `bitwise_and(...)` -> Does the bitwise AND operation on each number in order. Note that with larger ranges of numbers this will + tend to 0. + - `bitwise_xor(...)` -> Does the bitwise XOR operation on each number in order. + - `bitwise_or(...)` -> Does the bitwise AND operation on each number in order. Note that with larger ranges of numbers this will + tend to -1. + - `bitwise_shift_left(num, amount)` -> Shifts all the bits of the first number `amount` spots to the left. Note that shifting more + than 63 positions will result in a 0 (cos you shift out all the bits of the number) + - `bitwise_shift_right(num, amount)` -> Shifts all the bits of the first number `amount` spots to the right. Like with the above, + shifting more than 63 bits results in a 0. + - `bitwise_roll_left(num, amount)` -> Rolls the bits of the first number `amount` bits to the left. This is basically where you + shift out the first `amount` bits and then add them on at the back, essentially 'rolling' the number. Note that unlike with + shifting, you can roll more than 63 bits at a time, as it just makes the number roll over more times, which isn't an issue + - `bitwise_roll_right(num, amount)` -> Same as above, just rolling in the other direction + - `bitwise_not(num)` -> Flips all the bits of the number. This is simply done by performing xor operation with -1, which in binary is + all ones. + - `bitwise_popcount(num)` -> Returns the number of ones in the binary representation of the number. For the number of zeroes, just + do 64 minus this number. + - `double_to_long_bits(num)` -> Returns a representation of the specified floating-point value according to the IEEE 754 floating-point + "double format" bit layout. + - `long_to_double_bits(num)` -> Returns the double value corresponding to a given bit representation. diff --git a/docs/scarpet/resources/editors/idea/1.txt b/docs/scarpet/resources/editors/idea/1.txt index bae7a5b3..5f9a7dcc 100644 --- a/docs/scarpet/resources/editors/idea/1.txt +++ b/docs/scarpet/resources/editors/idea/1.txt @@ -9,6 +9,15 @@ asinh atan atan2 atanh +bitwise_and +bitwise_or +bitwise_xor +bitwise_shift_left +bitwise_shift_right +bitwise_roll_left +bitwise_roll_right +bitwise_not +bitwise_popcount bool break call @@ -26,6 +35,7 @@ decreasing deg delete difference +double_to_long_bits equal exit fact @@ -46,6 +56,7 @@ length log log10 log1p +long_bits_to_double loop lower m @@ -113,4 +124,4 @@ upper values var vars -while \ No newline at end of file +while diff --git a/docs/scarpet/resources/editors/npp/scarpet.xml b/docs/scarpet/resources/editors/npp/scarpet.xml index 8ca6b850..8a6df073 100644 --- a/docs/scarpet/resources/editors/npp/scarpet.xml +++ b/docs/scarpet/resources/editors/npp/scarpet.xml @@ -32,6 +32,8 @@ sqrt max min abs round floor ceil then sum difference product quotient equal unique increasing decreasing nonincreasing nondecreasing or and + bitwise_or bitwise_and bitwise_xor bitwise_shift_left bitwise_shit_right bitwise_roll_left bitwise_roll_right bitwise_not bitwise_popcount + double_to_long_bits long_bits_to_double mandelbrot relu perlin simplex diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java index ba5cef6a..e4109da4 100644 --- a/src/main/java/carpet/script/Expression.java +++ b/src/main/java/carpet/script/Expression.java @@ -468,6 +468,12 @@ public class Expression addUnaryFunction(name, (v) -> new NumericValue(fun.apply(NumericValue.asNumber(v).getDouble()))); } + public void addMathematicalBinaryIntFunction(String name, BiFunction fun) + { + addBinaryFunction(name, (w, v) -> + new NumericValue(fun.apply(NumericValue.asNumber(w).getLong(), NumericValue.asNumber(v).getLong()))); + } + public void addMathematicalBinaryFunction(String name, BiFunction fun) { addBinaryFunction(name, (w, v) -> diff --git a/src/main/java/carpet/script/language/Operators.java b/src/main/java/carpet/script/language/Operators.java index f539656c..35964fc4 100644 --- a/src/main/java/carpet/script/language/Operators.java +++ b/src/main/java/carpet/script/language/Operators.java @@ -84,6 +84,30 @@ public class Operators { expression.addBinaryOperator("^", precedence.get("exponent^"), false, (v1, v2) -> new NumericValue(java.lang.Math.pow(NumericValue.asNumber(v1).getDouble(), NumericValue.asNumber(v2).getDouble()))); + expression.addFunction("bitwise_and", lv -> { + int size = lv.size(); + if (size == 0) return Value.NULL; + long accumulator = NumericValue.asNumber(lv.get(0)).getLong(); + for (Value v: lv.subList(1, size)) accumulator = accumulator & NumericValue.asNumber(v).getLong(); + return new NumericValue(accumulator); + }); + + expression.addFunction("bitwise_xor", lv -> { + int size = lv.size(); + if (size == 0) return Value.NULL; + long accumulator = NumericValue.asNumber(lv.get(0)).getLong(); + for (Value v: lv.subList(1, size)) accumulator = accumulator ^ NumericValue.asNumber(v).getLong(); + return new NumericValue(accumulator); + }); + + expression.addFunction("bitwise_or", lv -> { + int size = lv.size(); + if (size == 0) return Value.NULL; + long accumulator = NumericValue.asNumber(lv.get(0)).getLong(); + for (Value v: lv.subList(1, size)) accumulator = accumulator | NumericValue.asNumber(v).getLong(); + return new NumericValue(accumulator); + }); + // lazy cause RHS is only conditional expression.addLazyBinaryOperator("&&", precedence.get("and&&"), false, true, t -> Context.Type.BOOLEAN, (c, t, lv1, lv2) -> { // todo check how is optimizations going @@ -202,6 +226,40 @@ public class Operators { }); expression.addFunctionalEquivalence("<=", "nondecreasing"); + expression.addMathematicalBinaryIntFunction("bitwise_shift_left", (num, amount) -> { + return num << amount; + }); + expression.addMathematicalBinaryIntFunction("bitwise_shift_right", (num, amount) -> { + return num >> amount; + }); + expression.addMathematicalBinaryIntFunction("bitwise_roll_left", (num, num2) -> { + long amount = num2 % 64; + + long amountToRoll = 64 - amount; + long rolledBits = ((-1L) >> amountToRoll) << amountToRoll; + long rolledAmount = (num & rolledBits) >> amountToRoll; + return num << amount | rolledAmount; + }); + expression.addMathematicalBinaryIntFunction("bitwise_roll_right", (num, num2) -> { + long amount = num2 % 64; + + long amountToRoll = 64 - amount; + long rolledBits = ((-1L) << amountToRoll) >> amountToRoll; + long rolledAmount = (num & rolledBits) << amountToRoll; + return num >> amount | rolledAmount; + }); + expression.addMathematicalUnaryIntFunction("bitwise_not", d -> { + long num = d.longValue(); + return num ^ (-1L); + }); + expression.addMathematicalUnaryIntFunction("bitwise_popcount", d -> Long.valueOf(Long.bitCount(d.longValue()))); + + expression.addMathematicalUnaryIntFunction("double_to_long_bits", Double::doubleToLongBits); + expression.addUnaryFunction("long_to_double_bits", v -> { + return new NumericValue(Double.longBitsToDouble(NumericValue.asNumber(v).getLong())); + }); + + expression.addBinaryOperator("==", precedence.get("equal==!="), false, (v1, v2) -> v1.equals(v2) ? Value.TRUE : Value.FALSE); expression.addFunction("equal", lv -> {