Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement fromNumber() #223

Closed
cliffhall opened this issue Jul 27, 2019 · 8 comments
Closed

Implement fromNumber() #223

cliffhall opened this issue Jul 27, 2019 · 8 comments

Comments

@cliffhall
Copy link

cliffhall commented Jul 27, 2019

I'm amazed that there is no easy way to create a BN from a JavaScript number without converting that number to a string and using the BN constructor, like:
const my BN = new BN(Number(90125).toString(), 10);

Instead, I'd like to do something like:
const myBN = BN.fromNumber(90125)

@fanatid
Copy link
Collaborator

fanatid commented Jul 27, 2019

Do you mean from Number which Object?

> typeof new Number(123)
'object'

@cliffhall
Copy link
Author

@fanatid No. I mean there is no functionality for creating a new BN from a Number. The BN constructor takes a string and a radix. Therefore I have to convert a number to a string before I can create a new BN with it. And unless I missed it, there's no utility function for taking a JavaScript Number and returning a equivalent BN instance.

@fanatid
Copy link
Collaborator

fanatid commented Jul 27, 2019

Actually, it's possible..

> new BN(42).muln(2)
BN { negative: 0, words: [ 84 ], length: 1, red: null }

this._init(number || 0, base || 10, endian || 'be');

bn.js/lib/bn.js

Lines 77 to 79 in f953de2

if (typeof number === 'number') {
return this._initNumber(number, base, endian);
}

bn.js/lib/bn.js

Lines 113 to 141 in f953de2

BN.prototype._initNumber = function _initNumber (number, base, endian) {
if (number < 0) {
this.negative = 1;
number = -number;
}
if (number < 0x4000000) {
this.words = [ number & 0x3ffffff ];
this.length = 1;
} else if (number < 0x10000000000000) {
this.words = [
number & 0x3ffffff,
(number / 0x4000000) & 0x3ffffff
];
this.length = 2;
} else {
assert(number < 0x20000000000000); // 2 ^ 53 (unsafe)
this.words = [
number & 0x3ffffff,
(number / 0x4000000) & 0x3ffffff,
1
];
this.length = 3;
}
if (endian !== 'le') return;
// Reverse the bytes
this._initArray(this.toArray(), base, endian);
};

@cliffhall
Copy link
Author

cliffhall commented Jul 27, 2019

@fanatid When I try to put a number into the constructor like:
const withdrawal = new BN(accounting.calcNet(itemAmount, franchiseFeePercent) * 2);

I get:
Screen Shot 2019-07-27 at 5 14 50 PM

In this case the amount the expression resolves to is 32642567254300000

If I change the line to convert the number to a string first:
const withdrawal = new BN(Number(accounting.calcNet(itemAmount, franchiseFeePercent) * 2).toString(), 10);

... it works:
Screen Shot 2019-07-27 at 5 20 09 PM

@cliffhall
Copy link
Author

cliffhall commented Jul 27, 2019

@fanatid I'm proposing a function along the lines of this:

BN.fromNumber = function fromNumber (jsNum) {
  
  return typeof jsNum === "number" ? new BN(jsNum.toString(), 10) : null;

}

Please note, I'm happy to make a PR with the function. There are definitely cases where it's needed and where conversion to string does the trick. It seems something's up with some JS number values when executing this assertion.

@fanatid
Copy link
Collaborator

fanatid commented Jul 28, 2019

Number 32642567254300000 is unsafe, because this error raised.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER

> 32642567254300000 <= Number.MAX_SAFE_INTEGER
false

What we actually need this is better error message, not new function.

@cliffhall
Copy link
Author

cliffhall commented Jul 28, 2019 via email

@fanatid
Copy link
Collaborator

fanatid commented Jul 28, 2019

While functions for creating BN from string/number/etc probably would be helpful, I do not think that will be changed. BN used in too much things and if tomorrow major version will be released with functions which should be used instead constructor thousands packages will need change code a lot.
I do not think that converting unsafe numbers implicitly in BN is correct thing. If people want create BN from unsafe numbers they should do this in their code, otherwise at one day somebody will blame BN that precision was lost here.

PR's for better error messages / documentations is highly welcome!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants