Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1339x 1339x 1339x 1339x 1339x 1339x 1339x 1339x 1339x 589x 589x 589x 750x 750x 750x 1x 1x 1x 1x 1x 1x 1x 1x 3199x 3199x 3199x 3199x 3199x 3199x 649x 649x 649x 649x 649x 649x 3199x 2550x 2550x 2550x 2550x 2550x 2550x 2550x 1x 1x 1x 1x 1x 7699x 7699x 7699x 7699x 1x 1x 1x 1x 1x 1x 3175808x 3175808x 3175808x 430540x 430540x 430540x 3175808x 489894x 489894x 489894x 641x 641x 489252x 489894x 3x 3x 3175808x 3175808x 3175808x 1x 1x 1x 1x 1x 1x 1498692x 1498692x 1498692x 1498692x 1498692x 1498692x 1x 1x 1x 1x 1x 1x 1x 1x 42636x 42636x 42636x 2264352x 2264352x 2264352x 42636x 42636x 1x 1x 1x 1x 1x 1x 252456x 252456x 45886x 45886x 252456x 168402x 168402x 168402x 252456x 38167x 38167x 38166x 38167x 3x 3x 252456x 252456x 252456x 1x 1x 1x 1x 1x 1x 1x 7340x 7340x 1x 1x 1x 1x 1x 1x 36011x 36011x 36011x 36011x 36011x 1x 1x 36011x 36009x 36009x 36009x 36009x 36009x 36009x 36009x 36009x 36009x 36009x 36009x 36009x 36009x 36009x 36009x 36009x 36009x 36009x 1x 1x 1x 1x 1x 1453643x 1453643x 1453643x 523501x 523501x 523501x 930141x 930141x 1453643x 930141x 1453643x 930141x 930141x 1453643x 11193750x 11193750x 11193750x 930141x 930141x 930141x 1x 1x 1x 1x 1x 1x 1x 1x 1x 132x 132x 132x 132x 132x | /**
* Some mathematic operations.
*
* @_subsection: api/utils:Math Helpers [about-maths]
*/
import { hexlify, isBytesLike } from "./data.js";
import { assert, assertArgument } from "./errors.js";
import type { BytesLike } from "./data.js";
/**
* Any type that can be used where a numeric value is needed.
*/
export type Numeric = number | bigint;
/**
* Any type that can be used where a big number is needed.
*/
export type BigNumberish = string | Numeric;
const BN_0 = BigInt(0);
const BN_1 = BigInt(1);
//const BN_Max256 = (BN_1 << BigInt(256)) - BN_1;
// IEEE 754 support 53-bits of mantissa
const maxValue = 0x1fffffffffffff;
/**
* Convert %%value%% from a twos-compliment representation of %%width%%
* bits to its value.
*
* If the highest bit is ``1``, the result will be negative.
*/
export function fromTwos(_value: BigNumberish, _width: Numeric): bigint {
const value = getUint(_value, "value");
const width = BigInt(getNumber(_width, "width"));
assert((value >> width) === BN_0, "overflow", "NUMERIC_FAULT", {
operation: "fromTwos", fault: "overflow", value: _value
});
// Top bit set; treat as a negative value
if (value >> (width - BN_1)) {
const mask = (BN_1 << width) - BN_1;
return -(((~value) & mask) + BN_1);
}
return value;
}
/**
* Convert %%value%% to a twos-compliment representation of
* %%width%% bits.
*
* The result will always be positive.
*/
export function toTwos(_value: BigNumberish, _width: Numeric): bigint {
let value = getBigInt(_value, "value");
const width = BigInt(getNumber(_width, "width"));
const limit = (BN_1 << (width - BN_1));
if (value < BN_0) {
value = -value;
assert(value <= limit, "too low", "NUMERIC_FAULT", {
operation: "toTwos", fault: "overflow", value: _value
});
const mask = (BN_1 << width) - BN_1;
return ((~value) & mask) + BN_1;
} else {
assert(value < limit, "too high", "NUMERIC_FAULT", {
operation: "toTwos", fault: "overflow", value: _value
});
}
return value;
}
/**
* Mask %%value%% with a bitmask of %%bits%% ones.
*/
export function mask(_value: BigNumberish, _bits: Numeric): bigint {
const value = getUint(_value, "value");
const bits = BigInt(getNumber(_bits, "bits"));
return value & ((BN_1 << bits) - BN_1);
}
/**
* Gets a BigInt from %%value%%. If it is an invalid value for
* a BigInt, then an ArgumentError will be thrown for %%name%%.
*/
export function getBigInt(value: BigNumberish, name?: string): bigint {
switch (typeof(value)) {
case "bigint": return value;
case "number":
assertArgument(Number.isInteger(value), "underflow", name || "value", value);
assertArgument(value >= -maxValue && value <= maxValue, "overflow", name || "value", value);
return BigInt(value);
case "string":
try {
if (value === "") { throw new Error("empty string"); }
if (value[0] === "-" && value[1] !== "-") {
return -BigInt(value.substring(1));
}
return BigInt(value);
} catch(e: any) {
assertArgument(false, `invalid BigNumberish string: ${ e.message }`, name || "value", value);
}
}
assertArgument(false, "invalid BigNumberish value", name || "value", value);
}
/**
* Returns %%value%% as a bigint, validating it is valid as a bigint
* value and that it is positive.
*/
export function getUint(value: BigNumberish, name?: string): bigint {
const result = getBigInt(value, name);
assert(result >= BN_0, "unsigned value cannot be negative", "NUMERIC_FAULT", {
fault: "overflow", operation: "getUint", value
});
return result;
}
const Nibbles = "0123456789abcdef";
/*
* Converts %%value%% to a BigInt. If %%value%% is a Uint8Array, it
* is treated as Big Endian data.
*/
export function toBigInt(value: BigNumberish | Uint8Array): bigint {
if (value instanceof Uint8Array) {
let result = "0x0";
for (const v of value) {
result += Nibbles[v >> 4];
result += Nibbles[v & 0x0f];
}
return BigInt(result);
}
return getBigInt(value);
}
/**
* Gets a //number// from %%value%%. If it is an invalid value for
* a //number//, then an ArgumentError will be thrown for %%name%%.
*/
export function getNumber(value: BigNumberish, name?: string): number {
switch (typeof(value)) {
case "bigint":
assertArgument(value >= -maxValue && value <= maxValue, "overflow", name || "value", value);
return Number(value);
case "number":
assertArgument(Number.isInteger(value), "underflow", name || "value", value);
assertArgument(value >= -maxValue && value <= maxValue, "overflow", name || "value", value);
return value;
case "string":
try {
if (value === "") { throw new Error("empty string"); }
return getNumber(BigInt(value), name);
} catch(e: any) {
assertArgument(false, `invalid numeric string: ${ e.message }`, name || "value", value);
}
}
assertArgument(false, "invalid numeric value", name || "value", value);
}
/**
* Converts %%value%% to a number. If %%value%% is a Uint8Array, it
* is treated as Big Endian data. Throws if the value is not safe.
*/
export function toNumber(value: BigNumberish | Uint8Array): number {
return getNumber(toBigInt(value));
}
/**
* Converts %%value%% to a Big Endian hexstring, optionally padded to
* %%width%% bytes.
*/
export function toBeHex(_value: BigNumberish, _width?: Numeric): string {
const value = getUint(_value, "value");
let result = value.toString(16);
if (_width == null) {
// Ensure the value is of even length
if (result.length % 2) { result = "0" + result; }
} else {
const width = getNumber(_width, "width");
// Special case when both value and width are 0 (see: #5025)
if (width === 0 && value === BN_0) { return "0x"; }
assert(width * 2 >= result.length, `value exceeds width (${ width } bytes)`, "NUMERIC_FAULT", {
operation: "toBeHex",
fault: "overflow",
value: _value
});
// Pad the value to the required width
while (result.length < (width * 2)) { result = "0" + result; }
}
return "0x" + result;
}
/**
* Converts %%value%% to a Big Endian Uint8Array.
*/
export function toBeArray(_value: BigNumberish, _width?: Numeric): Uint8Array {
const value = getUint(_value, "value");
if (value === BN_0) {
const width = (_width != null) ? getNumber(_width, "width"): 0;
return new Uint8Array(width);
}
let hex = value.toString(16);
if (hex.length % 2) { hex = "0" + hex; }
if (_width != null) {
const width = getNumber(_width, "width");
while (hex.length < (width * 2)) { hex = "00" + hex; }
assert((width * 2) === hex.length, `value exceeds width (${ width } bytes)`, "NUMERIC_FAULT", {
operation: "toBeArray",
fault: "overflow",
value: _value
});
}
const result = new Uint8Array(hex.length / 2);
for (let i = 0; i < result.length; i++) {
const offset = i * 2;
result[i] = parseInt(hex.substring(offset, offset + 2), 16);
}
return result;
}
/**
* Returns a [[HexString]] for %%value%% safe to use as a //Quantity//.
*
* A //Quantity// does not have and leading 0 values unless the value is
* the literal value `0x0`. This is most commonly used for JSSON-RPC
* numeric values.
*/
export function toQuantity(value: BytesLike | BigNumberish): string {
let result = hexlify(isBytesLike(value) ? value: toBeArray(value)).substring(2);
while (result.startsWith("0")) { result = result.substring(1); }
if (result === "") { result = "0"; }
return "0x" + result;
}
|