Does the number -0 exists in Javascript? - javascript

I was doing some money calculation and I got the number -0. This number -0 does not exists, since 0 does not have a sign. Why is this happening? I know the original price has more digits on my bd. but anyway this behaviour thing is weird anyway.
So I'm using this math expression: I pick the item price and subtract the discount, then I round it up.
(19.99923-20).toFixed(2)
And I get "-0.00" !? this is ugly to display. I tried using the Number() to make it a "real number", but
Number((19.99923-20).toFixed(1))
will appear as "-0".
What's wrong with javascript, there is no number -0, it should be just "0"?

JavaScript keeps sign with floating negatives close to 0, either using Math.round() or toFixed(), both can get you a -0. Solved that applying a quick fix, which consists in checking if our number enters that range in between 0 and -0.005 (rounded to -0.01 later). Considered 2 floating digits as your example works with money, so I considered a difference of 1 cent relevant:
var num=19.99923-20;
if(num>-0.005 && num<0){
num=0; //we set to '0' all -0
}else{
num=num*100;
num=Math.round(num);
num=num/100;
/*or
num=num.toFixed(2);
but this way we convert number to string*/
}
Hope it helps.

toFixed converts a number to string, not a number. So the -0.00 you are seeing is a string. Its the result of converting
19.99923-20 // which is about
-0.0007699999999992713 // in internal representation
to a string using the toFixed method in ECMAscript standards, which initialises the result to "-" for negative numbers and proceeds to convert the absolute (positive) value of the number being converted.
Converting the string "-0.00" back to a number with either parseFloat("-0.00") or Number("-0.00") returns a positive zero number representation (javscript stores numbers using the IEEE 754 standard for double precision float representation, which does have a negative zero value, but it's not the problem here.)
Looking at how toFixed works suggests the only problem is with a "-0.00" result, which can be checked using string comparison:
var number = 19.99923-20;
var str = number.toFixed(2);
if( str == "-0.00")
str = "0.00";
Alternatively you could consider using a conversion routine which never returns a negatively signed zero string such as:
function convertFixed( number, digits) {
if(isNaN(number))
return "NaN";
var neg = number < 0;
if( neg)
number = -number;
var string = number.toFixed(digits);
if( neg && Number(string) === 0) // negative zero result
neg = false;
return neg ? "-" + string : string;
}

Related

Convert number to BigInt or String when it's value exceeds Number.MAX_SAFE_INTEGER in ECMAScript

When we don't know the numerical value at advance, can we convert it to BigInt or String without value corruption?
const targetNumber: number = 90071992547409946; // suppose we don't know it in advance
function splitEach3DigitsGroupWithComma(targetNumber: number | bigint | string): string {
if(targetNumber > Number.MAX_SAFE_INTEGER) {
// targetNumber = BigInt(targetNumber); // 90071992547409952n
// targetNumber = String(targetNumber); // 90071992547409950
// We need to do something before proceed!
}
return String(targetNumber).replace(/\B(?=(?:\d{3})+(?!\d))/gu, ",");
}
If the targetNumber is neither already a BigInt nor a string at the point where you first can work with it, then it's a plain number - and in that case, it may only be as precise as a number can be, per the IEEE 754 standard. If you only have a number to work with to begin with, possible more precise values have already been lost earlier.
To maintain precision, ensure that the value stays as a BigInt or string from beginning to end. If it gets converted to a number at any time in between, and then that number gets used, it may have lost precision, depending on the number.
In other words, to do something like this, you need to start with something like
const targetNumber = '90071992547409946';
or
const targetNumber = 90071992547409946n;
It can't be done in the middle of the process, once you already only have a number, while maintaining precision.
If your number is bigger than Number._MAX_SAFE_INTEGER then you can not safely convert into BigInt as is.
Say your big integer is 134640597783270600 which is > Number._MAX_SAFE_INTEGER. If you do like
> n = 134640597783270600;
> BigInt(n);
<- 134640597783270592n // Wrong..!
So you should first check if n is bigger than Number._MAX_SAFE_INTEGER and if so just convert it to string first
> BigInt(n > Number.MAX_SAFE_INTEGER ? n+"" : n);
<- 134640597783270600n // Correct..!
However, if n happens to be a big integer expressed in the exponential form like 7.576507751994453e+29 then this happens;
> BigInt(7.576507751994453e+29+"");
Uncaught SyntaxError: Cannot convert 7.576507751994453e+29 to a BigInt
at BigInt (<anonymous>)
at <anonymous>:1:1
At this time i think to be on the safe side, it's best to convert all those integers greater than Number.MAX_SAFE_INTEGER into String type first to test for exponential representation. So, despite we have a BigInt constructor in JS, apparently we still need a function.
function toBigInt(n){
return n.toString().includes("e") ? BigInt(n)
: BigInt(n+"");
}

Converting a Two's complement number to its binary representation

I am performing bitwise operations, the result of which is apparently being stored as a two's complement number. When I hover over the variable it's stored in I see- num = -2086528968.
The binary of that number that I want is - (10000011101000100001100000111000).
But when I say num.toString(2) I get a completely different binary representation, the raw number's binary instead of the 2s comp(-1111100010111011110011111001000).
How do I get the first string back?
Link to a converter: rapidtables.com/convert/number/decimal-to-binary.html
Put in this number: -2086528968
Follow bellow the result:
var number = -2086528968;
var bin = (number >>> 0).toString(2)
//10000011101000100001100000111000
console.log(bin)
pedro already answered this, but since this is a hack and not entirely intuitive I'll explain it.
I am performing bitwise operations, the result of which is apparently being stored as a two's complement number. When I hover over the variable its stored in I see num = -2086528968
No, the result of most bit-operations is a 32bit signed integer. This means that the bit 0x80000000 is interpreted as a sign followed by 31 bits of value.
The weird bit-sequence is because of how JS stringifies the value, something like sign + Math.abs(value).toString(base);
How to deal with that? We need to tell JS to not interpret that bit as sign, but as part of the value. But how?
An easy to understand solution would be to add 0x100000000 to the negative numbers and therefore get their positive couterparts.
function print(value) {
if (value < 0) {
value += 0x100000000;
}
console.log(value.toString(2).padStart(32, 0));
}
print(-2086528968);
Another way would be to convert the lower and the upper bits seperately
function print(value) {
var signBit = value < 0 ? "1" : "0";
var valueBits = (value & 0x7FFFFFFF).toString(2);
console.log(signBit + valueBits.padStart(31, 0));
}
print(-2086528968);
//or lower and upper half of the bits:
function print2(value) {
var upperHalf = (value >> 16 & 0xFFFF).toString(2);
var lowerHalf = (value & 0xFFFF).toString(2);
console.log(upperHalf.padStart(16, 0) + lowerHalf.padStart(16, 0));
}
print2(-2086528968);
Another way involves the "hack" that pedro uses. You remember how I said that most bit-operations return an int32? There is one operation that actually returns an unsigned (32bit) interger, the so called Zero-fill right shift.
So number >>> 0 does not change the bits of the number, but the first bit is no longer interpreted as sign.
function uint32(value){
return value>>>0;
}
function print(value){
console.log(uint32(value).toString(2).padStart(32, 0));
}
print(-2086528968);
will I run this shifting code only when the number is negative, or always?
generally speaking, there is no harm in running nr >>> 0 over positive integers, but be careful not to overdo it.
Technically JS only supports Numbers, that are double values (64bit floating point values). Internally the engines also use int32 values; where possible. But no uint32 values. So when you convert your negative int32 into an uint32, the engine converts it to a double. And if you follow up with another bit operation, first thing it does is converting it back.
So it's fine to do this like when you need an actual uint32 value, like to print the bits here, but you should avoid this conversion between operations. Like "just to fix it".

remove leading 0 before decimal point and return as a number- javascript

Problem
I need to return a number in the format of .66 (from an entered value which includes the leading zero, e.g. 0.66)
It must be returned as an integer with the decimal point as the first character.
what method in JavaScript can help me do this?
What have I tried?
I've tried converting it toString() and back to parseInt() but including the decimal point makes it return NaN.
I've tried adding various radix (10, 16) to my parseInt() - also unsuccessful
Sample Code
const value = 0.66;
if(value < 1) {
let str = value.toString().replace(/^0+/, '');
// correctly gets '.66'
return parseInt(str)
}
//result NaN
Expectations
I expect an output of the value with the leading 0 removed
e.g. 0.45 --> .45 or 0.879 --> .879
Current Observations
Output is NaN
I tried a quick solution, you may try to do this:
let a = 0.45;
// split on decimal, at index 1 you will find the number after decimal
let b = a.toString().split('.')[1];
Issue #1:
0.66 is not an Integer. An Integer is a whole number, this is a floating-point number.
Issue #2:
You cannot have a number in JavaScript that starts with a decimal point.
Even if you change your parseInt to be parseFloat, it will still return 0.66 as a result.
What you're asking just isn't possible, if you want a number to start with a decimal point then it has to be a string.

how do i convert number starting with decimal to zero

I need to convert number starting with decimal like .15 to 0 rather then 0.15 in javascript.
using ParseInt(value) only work for leading zero numbers like 001 or 0.1.
can anyone provide me good solution ??
An input value is a String! Trying to use parseInt on a non-number (string decimal missing integer) will result in NaN when the parser tries to perform a string-to-number conversion:
parseInt(".15", 10) // NaN
In that case you need to first convert it to a Number:
parseInt(Number(".15"), 10) // 0
(or using the Unary +)
parseInt( +".15", 10) // 0

Is this a valid way to truncate a number?

I found this code in a SO answer as a way to truncate a number into an integer in Javascript:
var num = -20.536;
var result = num | 0;
//result = -20
Is this a valid way to truncate a number in Javascript, or it is some kind of hack? Why does it works only with numbers less than 2147483647?
That method works by implicitly converting the number to a 32-bit integer, as binary operators use 32-bit integers in their calculations.
The drawbacks of that method are:
The desired operation is hidden as an implicit effect of the operator, so it's not easy to see what the intention of the code is.
It can only handle integers within the range of a 32-bit number.
For any regular case you should use the Math.floor or Math.ceil methods instead, it clearly shows what the intention of the code is, and it handles any number within the precision range of a double, i.e. integers up to 52 bits:
var num = 20.536;
var result = Math.floor(num); // 20
var num = -20.536;
var result = Math.ceil(num); // -20
There is no round-towards-zero method in Javascript, so to do that you would need to check the sign before rounding:
var result = num < 0 ? Math.ceil(num) : Math.floor(num);
Use Javascript's parseInt like so:
var num = -20.536;
var num2int = parseInt(num);
return num2int; //returns -20
Tada! num is now an int with the value of -20.
If you use parseInt you can go from -2^53 to +2^53:
parseInt(-20.536) // -20
parseInt(9007199254740992.1234) // 9007199254740992
Why +/- 2^53? This is because JavaScript uses a 64-bit representation for floating point numbers, with a 52-bit mantissa. Hence all integer values up to 2^53 can be represented exactly. Beyond this, whole numbers are approximated.

Categories

Resources