maxgraey / as-bignum Goto Github PK
View Code? Open in Web Editor NEWFixed length big numbers for AssemblyScript ๐
License: Apache License 2.0
Fixed length big numbers for AssemblyScript ๐
License: Apache License 2.0
My test case
as
export function test (a: u64, b: u64): u64 {
return (u128Safe.from(a) % u128Safe.from(b)).toU64()
}
js
console.log(test(19n, 2n)) // outputs 0
I'm working on a project that's very interested in this package becoming production ready. Please DM and I'd love to talk about how we can help complete this library's implementation, whether you need more dev hands or sponsorship.
Email: [email protected]
Telegram: @dOrgJelli
Kind Regards,
Jordan
Current PR #7 (thanks @javiersuweijie) added naive reminder/division implementations which quite good works when numerator and denominator pretty close. So for future need to choose and implement more performant alghoritm for hard case.
It would be nice if it is possible to do
u128Val: u128 = 1;
but currently this causes the following error
ERROR AS200: Conversion from type 'i32' to 'bignum/integer/u128/u128' requires an explicit cast.
Here are a few simple test cases:
it("Should add 0 and 1", () => {
var a = u256.Zero;
var b = u256.One;
expect<u256>(a + b).toStrictEqual(b);
var c = new u256(0xffffffffffffffff, 0, 0, 0);
var res = new u256(0, 1, 0, 0);
expect<u256>(b + c).toStrictEqual(res);
c = new u256(0xffffffffffffffff, 0xffffffffffffffff, 0, 0);
res = new u256(0, 0, 1, 0);
expect<u256>(b + c).toStrictEqual(res);
});
it("Should sub numbers", () => {
var a = u256.Zero;
var b = u256.One;
expect<u256>(b - a).toStrictEqual(b);
expect<u256>(b - b).toStrictEqual(a);
});
I see two issues. First this should probably be a.lo2
and b.lo2
here:
Then, mid
's carry is lost, I don't think this is correct:
I think generally since u128
doesn't return carry, it makes it hard to use it in u256
.
v0.25 ~ v0.27
TS2322: Type '~lib/as-bignum/assembly/integer/u128/u128 | null' is not assignable to type '~lib/as-bignum/assembly/integer/u128/u128'.
:
278 โ return value === null || !(value.lo | value.hi);
โ ~~~~
โโ in ~lib/as-bignum/assembly/integer/u128.ts(278,22)
TODO
Error: Import file '~lib/internal/arraybuffer.ts' not found.
at v (C:\Users\jtenner\Desktop\projects\near-runtime-ts\node_modules\assemblyscript\dist\asc.js:1:528413)
at Object.exports.main (C:\Users\jtenner\Desktop\projects\near-runtime-ts\node_modules\assemblyscript\dist\asc.js:1:529177)
at C:\Users\jtenner\Desktop\projects\near-runtime-ts\node_modules\as-pect\lib\cli\run.js:183:27
at Array.forEach (<anonymous>)
at Object.run (C:\Users\jtenner\Desktop\projects\near-runtime-ts\node_modules\as-pect\lib\cli\run.js:182:36)
at Object.asp (C:\Users\jtenner\Desktop\projects\near-runtime-ts\node_modules\as-pect\lib\cli\index.js:68:19)
at Object.<anonymous> (C:\Users\jtenner\Desktop\projects\near-runtime-ts\node_modules\as-pect\bin\asp:2:32)
at Module._compile (internal/modules/cjs/loader.js:774:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:785:10)
at Module.load (internal/modules/cjs/loader.js:641:32)
This is the result of https://github.com/MaxGraey/bignum.wasm/blob/a25aea823a65e843b0888e00707f2dce9ddd01b3/assembly/integer/u128.ts#L1
because of line 111 & line 116 in assembly/integer/i128.ts
, the assemblyscript v0.18
complains that this
is not recognized.
may be we should change this
to i128
?
$ asc ./index.ts --noEmit --measure
ERROR TS6054: File '~lib/as-bignum.ts' not found.
:
3 โ export { i128, u128, u256 } from "as-bignum";
โ ~~~~~~~~~~~
โโ in assembly/index.ts(3,34)
In #56 we implemented muldiv
operation for u128
and safe/u128
but last one still required overflow checking
WARNING AS226: Expression resolves to unusual type 'usize'.
__multi3(null, a.lo, a.hi, b.lo, b.hi);
~~~~
in ~lib/as-bignum/integer/u128.ts(434,13)
Does this just need a type cast?
Currently different types in the library are in various stages of implementation completeness.
NEAR uses 128-bit numbers internally, therefore we need following types fully implemented:
u128
i128
safe.u128
safe.i128
Acceptance criteria:
u128
safe.
types also implement overflow check for all operations which can result in overflowDescribe the bug
Conversion of large positive f64
numbers to u128
fails with e.g.:
u128.fromF64(value)
fails with error: FunctionCallError(WasmTrap(IllegalArithmetic))
u128.fromString(value.toString())
fails by converting to a simple digit number (does not take into the fraction nor exponent).When the f64
value can be represented with an exponent e.g. 2.5e+23
To Reproduce
i have deployed the following smart contract to the following account f64-to-128.cristobal.testnet
:
Conversion for small values works fine e.g.:
export function small_values_ok():u128[] {
return [
u128.fromF64(parseFloat('10') as f64),
u128.fromF64(parseFloat('100') as f64),
u128.fromF64(parseFloat('1000') as f64),
u128.fromF64(parseFloat('10000') as f64),
u128.fromF64(parseFloat('100000') as f64),
u128.fromF64(parseFloat('10000000') as f64)
]
}
Conversion from f64
value fails e.g:
export function large_values_from_f64_fails(): u128[] {
return [
u128.fromF64(
parseFloat('1000000000000000000000000') as f64
)
]
}
Conversion from f64
string value also fails e.g.:
export function large_values_from_f64_string_fails(): u128[] {
return [
u128.fromString(
(parseFloat('1000000000000000000000000') as f64).toString()
)
]
}
Created a custom function that expands large float values that are represented with exponent e.g.:
function parseF64ValueToString(value: f64): string {
const repr = value.toString();
if (repr.indexOf('e+') < 0) {
return repr;
}
const elements = repr.split('e+');
const val = elements[0];
const args = [
val.charAt(0)
];
let stop = val.indexOf('0') > 0
? val.indexOf('0')
: val.length;
for (let i = 2; i < stop; i++) {
args.push(val.charAt(i));
}
const exp = parseInt(elements[1]) as i32;
stop = exp - (args.length - 1);
for (let i = 0; i < stop; i++) {
args.push('0');
}
return args.join('');
}
This is how the values are represented without expansion:
This is how the values are represented with expansion:
We can see that converting the expanded functions works fine:
export function large_values_ok(): u128[] {
return [
u128.fromString(
parseF64ValueToString(
parseFloat('1000000000000000000000000') as f64
)
),
u128.fromString(
parseF64ValueToString(
parseFloat('2500000000000000000000000') as f64
)
)
]
}
Expected behavior
Would expect that conversion for large float values to u128 should work as expected.
Perhaps the approach above could be a temporary solution until a proper approach is in place, i am no expert on web assembly and not sure how this should be done there.
Maybe some logic like this could be used here:
@inline
static fromF64(value: f64): u128 {
if (value.toString().indexOf('e+')) {
return fromString(parseF64ValueToString(value));
}
return new u128(<u64>value, reinterpret<i64>(value) >> 63);
}
Hi, My project depends on as-bignum very much, it does huge help for me. But the implementation of i128 leaves some methods like toArrayBufferLE
, toArrayBufferBE
etc, which exist on u128
.
Can we provide these functions in next version?
Thanks
What does the safe version refer to here? Is it similar to checked_op in rust? It seems that it is more convenient to introduce an Option, and in this case, it seems that new types should not be defined
Currently there are a lot of warnings like this
WARNING AS224: TODO: Cannot inline inferred calls and specific internals yet.
it >>= shift;
~~~~~~~~~~~~
in assembly/integer/u256.ts(515,8)
when I build the project. It seems that this happens only with the new runtime. It would be nice if we can fix it.
Relate to PR #13
Generate documentation via typedoc
Triplet of a * b / c
integer operations may overflow. So will be great have u128.mulDiv
operation which avoid overflow in multiplication part.
BigInt
.Tested by adding this failing case:
it("Should convert to hex", () => {
var a = new u128(90);
expect(a.toString(16)).toStrictEqual('5a');
});
new u128(90).toString(16) returns 55
, is this expected?
The reverse works fine:
it("Should convert from hex", () => {
expect(u128.from('0x5a'))
.toStrictEqual(u128.from(90));
});
Why not to build u256
on top of u128
? Implementation will be the same as u128
on top of u64
. Implementation can even be templated by subtype.
It'll be nice to have bignum.wasm published in main npm repository. It's very error-prone (and slow) to depend on packages on GitHub.
We might need to have to create own fork and publish ourselves if there is no official package.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.