diff --git a/README.md b/README.md
index 31039f1..ab168f1 100644
--- a/README.md
+++ b/README.md
@@ -202,6 +202,12 @@ API
* Long#**not**(): `Long`
Returns the bitwise NOT of this Long.
+* Long#**countLeadingZeros**/**clz**(): `number`
+ Returns count leading zeros of this Long.
+
+* Long#**countTrailingZeros**/**ctz**(): `number`
+ Returns count trailing zeros of this Long.
+
* Long#**notEquals**/**neq**/**ne**(other: `Long | number | string`): `boolean`
Tests if this Long's value differs from the specified's.
diff --git a/index.d.ts b/index.d.ts
index 1f1fd03..5472d8e 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -289,6 +289,26 @@ declare class Long {
*/
not(): Long;
+ /**
+ * Returns count leading zeros of this Long.
+ */
+ countLeadingZeros(): number;
+
+ /**
+ * Returns count leading zeros of this Long.
+ */
+ clz(): number;
+
+ /**
+ * Returns count trailing zeros of this Long.
+ */
+ countTrailingZeros(): number;
+
+ /**
+ * Returns count trailing zeros of this Long.
+ */
+ ctz(): number;
+
/**
* Tests if this Long's value differs from the specified's.
*/
diff --git a/index.js b/index.js
index 2fd859b..f04775e 100644
--- a/index.js
+++ b/index.js
@@ -2,7 +2,7 @@
* @license
* Copyright 2009 The Closure Library Authors
* Copyright 2020 Daniel Wirtz / The long.js Authors.
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -96,6 +96,17 @@ function isLong(obj) {
return (obj && obj["__isLong__"]) === true;
}
+/**
+ * @function
+ * @param {*} value number
+ * @returns {number}
+ * @inner
+ */
+function ctz32(value) {
+ var c = Math.clz32(value & -value);
+ return value ? 31 - c : c;
+}
+
/**
* Tests if the specified object is a Long.
* @function
@@ -1126,6 +1137,40 @@ LongPrototype.not = function not() {
return fromBits(~this.low, ~this.high, this.unsigned);
};
+/**
+ * Returns count leading zeros of this Long.
+ * @this {!Long}
+ * @returns {!number}
+ */
+LongPrototype.countLeadingZeros = function countLeadingZeros() {
+ return this.high ? Math.clz32(this.high) : Math.clz32(this.low) + 32;
+};
+
+/**
+ * Returns count leading zeros. This is an alias of {@link Long#countLeadingZeros}.
+ * @function
+ * @param {!Long}
+ * @returns {!number}
+ */
+LongPrototype.clz = LongPrototype.countLeadingZeros;
+
+/**
+ * Returns count trailing zeros of this Long.
+ * @this {!Long}
+ * @returns {!number}
+ */
+LongPrototype.countTrailingZeros = function countTrailingZeros() {
+ return this.low ? ctz32(this.low) : ctz32(this.high) + 32;
+};
+
+/**
+ * Returns count trailing zeros. This is an alias of {@link Long#countTrailingZeros}.
+ * @function
+ * @param {!Long}
+ * @returns {!number}
+ */
+LongPrototype.ctz = LongPrototype.countTrailingZeros;
+
/**
* Returns the bitwise AND of this Long and the specified.
* @this {!Long}
diff --git a/tests/index.js b/tests/index.js
index e5a4e4b..b935f9a 100644
--- a/tests/index.js
+++ b/tests/index.js
@@ -177,6 +177,7 @@ var tests = [ // BEGIN TEST CASES
v = longVal.rotateLeft(32);
assert.deepEqual(v, longValS);
},
+
function testRotateRight() {
var longVal = Long.fromBits(0x01234567, 0x89ABCDEF);
var longValL = Long.fromBits(0x12345678, 0x9ABCDEF0);
@@ -191,6 +192,23 @@ var tests = [ // BEGIN TEST CASES
// swap
v = longVal.rotateRight(32);
assert.deepEqual(v, longValS);
+ },
+
+ function testClzAndCtz() {
+ var longVal0 = Long.fromBits(0, 0);
+ var longVal1 = Long.fromBits(1, 0);
+ var longVal2 = Long.fromBits(0, 1);
+ var longVal3 = Long.fromBits(1, 1);
+
+ assert.deepEqual(longVal0.clz(), 64);
+ assert.deepEqual(longVal1.clz(), 63);
+ assert.deepEqual(longVal2.clz(), 31);
+ assert.deepEqual(longVal3.clz(), 31);
+
+ assert.deepEqual(longVal0.ctz(), 64);
+ assert.deepEqual(longVal1.ctz(), 0);
+ assert.deepEqual(longVal2.ctz(), 32);
+ assert.deepEqual(longVal3.ctz(), 0);
}
]; // END TEST CASES