Overwrite toFixed() with appropriate replacement to fix floating point error javascript - javascript

This is my attempt to fix the JavaScript toFixed() function...
Any input, ideas, corrections for possible errors are much appreciated!
Fix floating point inacurracy (example (35.355).toFixed(2) = 35.36, not 35.35)
No big additional libraries
Comprehensive function (readable by humans)
Mimics toFixed / i.e. outputs exactly the same (albeit with correction for floating point inac. or course)
This is my attempt -> Demo below (see console log)
Number.prototype.toFixed = function(fractionDigits) {
var digits = parseInt(fractionDigits) || 0;
var num = Number(this);
if( isNaN(num) ) {
return 'NaN';
}
var sign = num < 0 ? -1 : 1;
if (sign < 0) { num = -num; }
digits = Math.pow(10, digits);
num *= digits;
num = Math.round( Math.round(num * Math.pow(10,12)) / Math.pow(10,12) );
var finalNumber = sign * num / digits;
// add 0 after last decimal number (not 0) for as many as requested (fractionDigits)
// in else case, check if requested digits exceed actual, then add 0 (avoid 10.1 for toFixed(2))
if(fractionDigits > 0 && finalNumber.toString().indexOf('.') == -1){
// check that .00 is present
finalNumber = finalNumber.toString() + '.' + '0'.repeat(fractionDigits);
} else if(fractionDigits > finalNumber.toString().split('.')[1]?.length){
finalNumber = finalNumber.toString() + '0'.repeat((fractionDigits - finalNumber.toString().split('.')[1]?.length));
}
return finalNumber.toString(); // tofixed returns as string always, do the same
}
console.log('(35.355).toFixed(2)', (35.355).toFixed(2));
console.log('(35.1).toFixed(2)', (35.1).toFixed(2));
console.log('(35).toFixed(2)', (35).toFixed(2));
Number.prototype.toFixed = function(fractionDigits) {
//function toFixed(numberInput, fractionDigits){
var digits = parseInt(fractionDigits) || 0;
var num = Number(this);
if( isNaN(num) ) {
return 'NaN';
}
var sign = num < 0 ? -1 : 1;
if (sign < 0) { num = -num; }
digits = Math.pow(10, digits);
num *= digits;
num = Math.round( Math.round(num * Math.pow(10,12)) / Math.pow(10,12) );
var finalNumber = sign * num / digits;
// add 0 after last decimal number (not 0) for as many as requested (fractionDigits)
if(fractionDigits > 0 && finalNumber.toString().indexOf('.') == -1){
// check that .00 is present
finalNumber = finalNumber.toString() + '.' + '0'.repeat(fractionDigits);
} else if(fractionDigits > finalNumber.toString().split('.')[1]?.length){
finalNumber = finalNumber.toString() + '0'.repeat((fractionDigits - finalNumber.toString().split('.')[1]?.length));
}
return finalNumber.toString(); // tofixed returns as string always, do the same
}
console.log('post-fix | (35.355).toFixed(2)', (35.355).toFixed(2));
console.log('post-fix | (35.1).toFixed(2)', (35.1).toFixed(2));
console.log('post-fix | (35).toFixed(2)', (35).toFixed(2));

If it were me, I might have this string manipulation approach:
Number.prototype.toFixed = function(fractionDigits) {
var number = String(this);
var digits = fractionDigits || 0, length;
if(digits < 0 && digits > 100)
throw 'RangeError: toFixed() digits argument must be between 0 and 100';
var decimal = number.match(/(?<=\.)(\d*)/g);
var factor = Math.pow(10, digits);
if (decimal && decimal[0].length >= digits)
return String(Math.round(Number(number + '1') * factor) / factor);
else {
var length = digits - (decimal ? decimal[0].length : 0);
var delimiter = number.includes('.') || !length ? '' : '.';
return String(number) + delimiter + '0'.repeat(length);
}
}
function test() {
console.log((-35.555).toFixed(2))
console.log((-35.35).toFixed(2))
console.log((-35.9).toFixed(2))
console.log((-35).toFixed(2))
}
Note:
I think you're not going to encounter a string in your toFixed since it will not be triggered by it so you don't need isNaN check.
Catch beforehand when the parameter is less than 0 or greater than 100. This should throw an error like the original one.
Output:

Instead of rounding number num = Math.round( Math.round(num * Math.pow(10,12)) / Math.pow(10,12) ); here you try parsing it to integer.
Math.round will round the value depending on its factorial part greater or less than 0.5. parseInt will simply fetch integer part without rounding, as you are expecting here.
console.log('(35.355).toFixed(2)', (35.355).toFixed(2));
console.log('(35.1).toFixed(2)', (35.1).toFixed(2));
console.log('(35).toFixed(2)', (35).toFixed(2));
Number.prototype.toFixed = function(fractionDigits) {
//function toFixed(numberInput, fractionDigits){
debugger;
var digits = parseInt(fractionDigits) || 0;
var num = Number(this);
if( isNaN(num) ) {
return 'NaN';
}
var sign = num < 0 ? -1 : 1;
if (sign < 0) { num = -num; }
digits = Math.pow(10, digits);
num *= digits;
num = parseInt( Math.round(num * Math.pow(10,12)) / Math.pow(10,12) );
var finalNumber = sign * num / digits;
// add 0 after last decimal number (not 0) for as many as requested (fractionDigits)
if(fractionDigits > 0 && finalNumber.toString().indexOf('.') == -1){
// check that .00 is present
finalNumber = finalNumber.toString() + '.' + '0'.repeat(fractionDigits);
} else if(fractionDigits > finalNumber.toString().split('.')[1]?.length){
finalNumber = finalNumber.toString() + '0'.repeat((fractionDigits - finalNumber.toString().split('.')[1]?.length));
}
return finalNumber.toString(); // tofixed returns as string always, do the same
}
console.log('post-fix | (35.355).toFixed(2)', (35.355).toFixed(2));
console.log('post-fix | (35.1).toFixed(2)', (35.1).toFixed(2));
console.log('post-fix | (35).toFixed(2)', (35).toFixed(2));

Related

Sum a negative number's digits

'Write a function named sumDigits which takes a number as input and
returns the sum of each of the number's decimal
digits.'
How can I sum the digits with the first digit being negative?
For example: sumDigits(-32); // -3 + 2 = -1;
I was able to solve it partially.
function sumDigits(number) {
return Math.abs(number).toString().split("").reduce(function(a, b) {
return parseInt(a) + parseInt(b);
}, 0);
}
console.log( sumDigits(-32) );
Simple math and recursion make short work of this problem.
Recall that when you divide a number by 10, the remainder is its rightmost decimal digit and the integer part of the quotient is the number formed by the remaining digits. In other words:
let n = 5678;
console.log(n % 10); // => 8
console.log(Math.floor(n / 10)); // => 567
With this in mind, summing a number's digits is a straightforward recursive procedure:
Procedure(n)
Divide n by 10.
Set digit to the remainder.
Set n to the integer part of the quotient.
If n = 0, return digit.
Otherwise, return digit + Procedure(n)
Keeping the sign for the leftmost digit adds a small amount of complexity, but not much. Here's how it looks in JavaScript:
function digitSum(n, sign=1) {
if (n < 0) {
sign = -1; // Save the sign
n = Math.abs(n);
}
const digit = n % 10; // Remainder of |n÷10|
n = Math.floor(n / 10); // Integer part of |n÷10|
if (n === 0) {
return sign * digit; // No digits left, return final digit with sign
}
return digit + digitSum(n, sign); // Add digit to sum of remaining digits
}
console.log(digitSum(32)); // => 5
console.log(digitSum(-32)); // => -1
Here is a way to do it with Array.prototype.reduce().
Stringify the input and split it on each character.
Iterate over the characters with reduce.
Initialize the accumulator with a sum of 0 and a multiplier of 1.
If the first character is a -, set the multiplier to -1
For the subsequent characters, multiply the digit with the multiplier and add it to the sum. Then set the multiplier back to 1 so the next digits will only be multiplied by 1.
const sumDigits = x => [...`${x}`].reduce(({ sum, mult }, x, i) => {
return i === 0 && x === '-' ? { sum: 0, mult: -1 } : { sum: sum + mult * x, mult: 1 };
}, { sum: 0, mult: 1 }).sum;
console.log(sumDigits(-32)); // -1
console.log(sumDigits(32)); // 5
console.log(sumDigits(5555)); // 20
Here's a way you can do it without String conversion -
const sumDigits = (n = 0) =>
n < 0
? n > -10
? n
: (-n % 10) + sumDigits (n / 10 >> 0)
: n < 10
? n
: (n % 10) + sumDigits (n / 10 >> 0)
console.log(sumDigits(-321))
// (-3 + 2 + 1)
// => 0
console.log(sumDigits(321))
// (3 + 2 + 1)
// => 6
The same answer using imperative style -
const sumDigits = (n = 0) =>
{ if (n < 0)
if (n > -10)
return n
else
return (-n % 10) + sumDigits (n / 10 >> 0)
else
if (n < 10)
return n
else
return (n % 10) + sumDigits (n / 10 >> 0)
}
console.log(sumDigits(-321))
// (-3 + 2 + 1)
// => 0
console.log(sumDigits(321))
// (3 + 2 + 1)
// => 6
An approach that does not require converting to a string adapted from another answer by #NinaScholz to a closely related question (for those that are bitwise shift operator challenged).
Converts the number to its absolute value, loops with modulus operator to sum the remainder after dividing by 10 until a ones value remains, and then subtracts the leftmost digit if the original number was negative.
const sumDigits = (n) => {
const negative = !!(n < 0);
let sum = 0;
let num = negative ? Math.abs(n) : n;
while (num) {
if (negative && num <= 10) {
sum -= num % 10;
} else {
sum += num % 10;
}
num = Math.floor(num / 10);
}
return sum;
};
console.log(sumDigits(-32));
// -1
You could take a different method for separating the digits and keep the first one with a possible sign.
'-32'.match(/-?\d/g)
returns
['-3', '2']
function sumDigits(number) {
return number.toString().match(/-?\d/g).reduce(function(a, b) {
return a + +b;
}, 0);
}
console.log(sumDigits(-32));
First, "decimal digits" means only the characters to the right of the decimal point. Converting the number to a string sets you up as JavaScript strings are arrays of characters. So, then it's just a matter of splitting out the decimal digits then summing them by iterating that array, then converting back to a number type.
//'Write a function named sumDigits which takes a number as input and returns the sum of each of the number's decimal digits.'
var a = 10.12345;
var b = -1012345;
function sumDigits(x){
var result = 0;
x = x.toString();
x = x.split('.')[1];
if (x == null){
//there's not decimal digits to sum!
return "there's not decimal digits to sum!"
}
for (var i = 0; i < x.length; i++) {
if (digit >= 0 && digit <= 9) { //just in case, probably unnecessary
var digit = Number(x[i]);
result = result + digit;
}
}
//if you care about negative uncomment this
//if(x[0] === "-"){
// result = result * -1;
//}
return result;
}
console.log(sumDigits(a));
console.log(sumDigits(b));
// try this to get the sum of negatives:
const sumOfNegative = (numbers) => {
let sum = 0;
numbers.forEach((number) => {
if (number < 0) {
sum += number;
}
});
return sum;
};

Extracting middle of string - JavaScript

I am trying to write an algorithm for this in JavaScript but I am getting a str.length is not a function...
function extractMiddle(str) {
var position;
var length;
if(str.length() % 2 == 1) {
position = str.length() / 2;
length = 1;
} else {
position = str.length() / 2 - 1;
length = 2;
}
result = str.substring(position, position + length)
}
extractMiddle("handbananna");
Because string length is not a function, it's a property.
function extractMiddle(str) {
var position;
var length;
if(str.length % 2 == 1) {
position = str.length / 2;
length = 1;
} else {
position = str.length / 2 - 1;
length = 2;
}
return str.substring(position, position + length)
}
console.log(extractMiddle("handbananna"));
Here is an another way to do this:
function extractMiddle(str) {
return str.substr(Math.ceil(str.length / 2 - 1), str.length % 2 === 0 ? 2 : 1);
}
// the most amazing
const getMiddle = s => s.substr(s.length - 1 >>> 1, (~s.length & 1) + 1);
// should return "dd"
console.log(getMiddle('middle'))
// >>> is an unsigned right shift bitwise operator. It's equivalent to division by 2, with truncation, as long as the length of the string does not exceed the size of an integer in Javascript.
// About the ~ operator, let's rather start with the expression n & 1. This will tell you whether an integer n is odd (it's similar to a logical and, but comparing all of the bits of two numbers). The expression returns 1 if an integer is odd. It returns 0 if an integer is even.
// If n & 1 is even, the expression returns 0.
// If n & 1 is odd, the expression returns 1.
// ~n & 1 inverts those two results, providing 0 if the length of the string is odd, and 1 if the length of the sting is even. The ~ operator inverts all of the bits in an integer, so 0 would become -1, 1 would become -2, and so on (the leading bit is always the sign).
// Then you add one, and you get 0+1 (1) characters if the length of the string is odd, or 1+1 (2) characters if the length of the string is even.
#author by jacobb
the link of the source is: https://codepen.io/jacobwarduk/pen/yJpAmK
That seemed to fix it!
function extractMiddle(str) {
var position;
var length;
if(str.length % 2 == 1) {
position = str.length / 2;
length = 1;
} else {
position = str.length / 2 - 1;
length = 2;
}
result = str.substring(position, position + length)
console.log(result);
}
https://jsfiddle.net/sd4z711y/
The first 'if' statement is to get the odd number while the 'else if' is to get the even number.
function getMiddle(s)
{
if (s.length % 2 == 1) {
return s.substring((s.length / 2)+1, (s.length / 2))
} else if (s.length % 2 == 0) {
return s.substring((s.length / 2)-1, (s.length / 2)+1)
}
}
console.log(getMiddle("handers"));
console.log(getMiddle("test"));
Here is my solution :-
function pri(word) {
if (!word) return 'word should have atleast one character';
let w = [...word].reduce((acc, val) => (val == ' ' ? acc : (acc += val)));
let res = '';
let length = word.length;
let avg = length / 2;
let temp = avg % 2;
if (temp == 0) {
res += word.charAt(avg - 1) + word.charAt(avg);
} else {
res += word.charAt(avg);
}
return res;
}
console.log(pri("Lime")); // even letter
console.log(pri("Apple")); // odd letter
console.log(pri("Apple is Fruit")); // String sequence with space
console.log(pri("")); // empty string
here is my solution
function getMiddle(s){
let middle = Math.floor(s.length/2);
return s.length % 2 === 0
? s.slice(middle-1, middle+1)
: s.slice(middle, middle+1);
}
function extractMiddle(s) {
return s.substr(Math.ceil(s.length / 2 - 1), s.length % 2 === 0 ? 2 : 1);
}
extractMiddle("handbananna");
str.length is a property. Just get rid of the parentheses. Example:
if (str.length == 44) {
length is a property of string, not a function. Do this instead:
str.length % 2 === 1
Also, use I suggest favoring === over ==
Since length is not a function, there is no need to use ().
function getMiddle(str) {
if(str.length % 2 === 0 ) {
return str.substr(str.length/2-1, 2);
} else {
return str.charAt(Math.floor(str.length/2));
}
}
console.log(getMiddle("middbkbcdle"));

How can I round to an arbitrary number of significant digits with JavaScript?

I tried below sample code
function sigFigs(n, sig) {
if ( n === 0 )
return 0
var mult = Math.pow(10,
sig - Math.floor(Math.log(n < 0 ? -n: n) / Math.LN10) - 1);
return Math.round(n * mult) / mult;
}
But this function is not working for inputs like
sigFigs(24730790,3) returns 24699999.999999996
and sigFigs(4.7152e-26,3) returns: 4.7200000000000004e-26
If anybody has working example please share.
Thanks.
You can try javascript inbuilt method-
Number( my_number.toPrecision(3) )
For Your case try
Number( 24730790.0.toPrecision(5) )
For your refrence and working example you can see link
First of all thanks to everybody, it would be a hard task without these snippets shared.
My value added, is the following snippet (see below for complete implementation)
parseFloat(number.toPrecision(precision))
Please note that if number is, for instance, 10000 and precision is 2, then number.toPrecision(precision) will be '1.0e+4' but parseFloat understands exponential notation.
It is also worth to say that, believe it or not, the algorithm using Math.pow and logarithms posted above, when run on test case formatNumber(5, 123456789) was giving a success on Mac (node v12) but rising and error on Windows (node v10). It was weird so we arrived at the solution above.
At the end I found this as the definitive implementation, taking advantage of all feedbacks provided in this post. Assuming we have a formatNumber.js file with the following content
/**
* Format number to significant digits.
*
* #param {Number} precision
* #param {Number} number
*
* #return {String} formattedValue
*/
export default function formatNumber (precision, number) {
if (typeof number === 'undefined' || number === null) return ''
if (number === 0) return '0'
const roundedValue = round(precision, number)
const floorValue = Math.floor(roundedValue)
const isInteger = Math.abs(floorValue - roundedValue) < Number.EPSILON
const numberOfFloorDigits = String(floorValue).length
const numberOfDigits = String(roundedValue).length
if (numberOfFloorDigits > precision) {
return String(floorValue)
} else {
const padding = isInteger ? precision - numberOfFloorDigits : precision - numberOfDigits + 1
if (padding > 0) {
if (isInteger) {
return `${String(floorValue)}.${'0'.repeat(padding)}`
} else {
return `${String(roundedValue)}${'0'.repeat(padding)}`
}
} else {
return String(roundedValue)
}
}
}
function round (precision, number) {
return parseFloat(number.toPrecision(precision))
}
If you use tape for tests, here there are some basic tests
import test from 'tape'
import formatNumber from '..path/to/formatNumber.js'
test('formatNumber', (t) => {
t.equal(formatNumber(4, undefined), '', 'undefined number returns an empty string')
t.equal(formatNumber(4, null), '', 'null number return an empty string')
t.equal(formatNumber(4, 0), '0')
t.equal(formatNumber(4, 1.23456789), '1.235')
t.equal(formatNumber(4, 1.23), '1.230')
t.equal(formatNumber(4, 123456789), '123500000')
t.equal(formatNumber(4, 1234567.890123), '1235000')
t.equal(formatNumber(4, 123.4567890123), '123.5')
t.equal(formatNumber(4, 12), '12.00')
t.equal(formatNumber(4, 1.2), '1.200')
t.equal(formatNumber(4, 1.234567890123), '1.235')
t.equal(formatNumber(4, 0.001234567890), '0.001235')
t.equal(formatNumber(5, 123456789), '123460000')
t.end()
})
How about automatic type casting, which takes care of exponential notation?
f = (x, n) => +x.toPrecision(n)
Testing:
> f (0.123456789, 6)
0.123457
> f (123456789, 6)
123457000
> f (-123456789, 6)
-123457000
> f (-0.123456789, 6)
-0.123457
> f (-0.123456789, 2)
-0.12
> f (123456789, 2)
120000000
And it returns a number and not a string.
Unfortunately the inbuilt method will give you silly results when the number is > 10, like exponent notation etc.
I made a function, which should solve the issue (maybe not the most elegant way of writing it but here it goes):
function(value, precision) {
if (value < 10) {
value = parseFloat(value).toPrecision(precision)
} else {
value = parseInt(value)
let significantValue = value
for (let i = value.toString().length; i > precision; i--) {
significantValue = Math.round(significantValue / 10)
}
for (let i = 0; significantValue.toString().length < value.toString().length; i++ ) {
significantValue = significantValue * 10
}
value = significantValue
}
return value
}
If you prefer having exponent notation for the higher numbers, feel free to use toPrecision() method.
if you want to specify significant figures left of the decimal place and replace extraneous placeholders with T B M K respectively
// example to 3 sigDigs (significant digits)
//54321 = 54.3M
//12300000 = 12.3M
const moneyFormat = (num, sigDigs) => {
var s = num.toString();
let nn = "";
for (let i = 0; i <= s.length; i++) {
if (s[i] !== undefined) {
if (i < sigDigs) nn += s[i];
else nn += "0";
}
}
nn = nn
.toString()
.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,")
.replace(",000,000,000", "B")
.replace(",000,000", "M")
.replace(",000", "k");
if (
nn[nn.length - 4] === "," &&
nn[nn.length - 2] === "0" &&
nn[nn.length - 1] === "0"
) {
let numLetter = "K";
if (parseInt(num) > 999999999999) numLetter = "T";
else if (parseInt(num) > 999999999) numLetter = "B";
else if (parseInt(num) > 999999) numLetter = "M";
console.log("numLetter: " + numLetter);
nn = nn.toString();
let nn2 = ""; // new number 2
for (let i = 0; i < nn.length - 4; i++) {
nn2 += nn[i];
}
nn2 += "." + nn[nn.length - 3] + numLetter;
nn = nn2;
}
return nn;
};

Javascript: convert a (hex) signed integer to a javascript value

I have a signed value given as a hex number, by example 0xffeb and want convert it into -21 as a "normal" Javascript integer.
I have written some code so far:
function toBinary(a) { //: String
var r = '';
var binCounter = 0;
while (a > 0) {
r = a%2 + r;
a = Math.floor(a/2);
}
return r;
}
function twoscompl(a) { //: int
var l = toBinaryFill(a).length;
var msb = a >>> (l-1);
if (msb == 0) {
return a;
}
a = a-1;
var str = toBinary(a);
var nstr = '';
for (var i = 0; i < str.length; i++) {
nstr += str.charAt(i) == '1' ? '0' : '1';
}
return (-1)*parseInt(nstr);
}
The problem is, that my function returns 1 as MSB for both numbers because only at the MSB of the binary representation "string" is looked. And for this case both numbers are 1:
-21 => 0xffeb => 1111 1111 1110 1011
21 => 0x15 => 1 0101
Have you any idea to implement this more efficient and nicer?
Greetings,
mythbu
Use parseInt() to convert (which just accepts your hex string):
parseInt(a);
Then use a mask to figure out if the MSB is set:
a & 0x8000
If that returns a nonzero value, you know it is negative.
To wrap it all up:
a = "0xffeb";
a = parseInt(a, 16);
if ((a & 0x8000) > 0) {
a = a - 0x10000;
}
Note that this only works for 16-bit integers (short in C). If you have a 32-bit integer, you'll need a different mask and subtraction.
I came up with this
function hexToInt(hex) {
if (hex.length % 2 != 0) {
hex = "0" + hex;
}
var num = parseInt(hex, 16);
var maxVal = Math.pow(2, hex.length / 2 * 8);
if (num > maxVal / 2 - 1) {
num = num - maxVal
}
return num;
}
And usage:
var res = hexToInt("FF"); // -1
res = hexToInt("A"); // same as "0A", 10
res = hexToInt("FFF"); // same as "0FFF", 4095
res = hexToInt("FFFF"); // -1
So basically the hex conversion range depends on hex's length, ant this is what I was looking for. Hope it helps.
Based on #Bart Friederichs I've come with:
function HexToSignedInt(num, numSize) {
var val = {
mask: 0x8 * Math.pow(16, numSize-1), // 0x8000 if numSize = 4
sub: -0x1 * Math.pow(16, numSize) //-0x10000 if numSize = 4
}
if((parseInt(num, 16) & val.mask) > 0) { //negative
return (val.sub + parseInt(num, 16))
}else { //positive
return (parseInt(num,16))
}
}
so now you can specify the exact length (in nibbles).
var numberToConvert = "CB8";
HexToSignedInt(numberToConvert, 3);
//expected output: -840
function hexToSignedInt(hex) {
if (hex.length % 2 != 0) {
hex = "0" + hex;
}
var num = parseInt(hex, 16);
var maxVal = Math.pow(2, hex.length / 2 * 8);
if (num > maxVal / 2 - 1) {
num = num - maxVal
}
return num;
}
function hexToUnsignedInt(hex){
return parseInt(hex,16);
}
the first for signed integer and
the second for unsigned integer
As I had to turn absolute numeric values to int32 values that range from -2^24 to 2^24-1,
I came up with this solution, you just have to change your input into a number through parseInt(hex, 16), in your case, nBytes is 2.
function toSignedInt(value, nBytes) { // 0 <= value < 2^nbytes*4, nBytes >= 1,
var hexMask = '0x80' + '00'.repeat(nBytes - 1);
var intMask = parseInt(hexMask, 16);
if (value >= intMask) {
value = value - intMask * 2;
}
return value;
}
var vals = [ // expected output
'0x00', // 0
'0xFF', // 255
'0xFFFFFF', // 2^24 - 1 = 16777215
'0x7FFFFFFF', // 2^31 -1 = 2147483647
'0x80000000', // -2^31 = -2147483648
'0x80000001', // -2^31 + 1 = -2147483647
'0xFFFFFFFF', // -1
];
for (var hex of vals) {
var num = parseInt(hex, 16);
var result = toSignedInt(num, 4);
console.log(hex, num, result);
}
var sampleInput = '0xffeb';
var sampleResult = toSignedInt(parseInt(sampleInput, 16), 2);
console.log(sampleInput, sampleResult); // "0xffeb", -21
Based on the accepted answer, expand to longer number types:
function parseSignedShort(str) {
const i = parseInt(str, 16);
return i >= 0x8000 ? i - 0x10000 : i;
}
parseSignedShort("0xffeb"); // -21
function parseSignedInt(str) {
const i = parseInt(str, 16);
return i >= 0x80000000 ? i - 0x100000000 : i;
}
parseSignedInt("0xffffffeb"); // -21
// Depends on new JS feature. Only supported after ES2020
function parseSignedLong(str) {
if (!str.toLowerCase().startsWith("0x"))
str = "0x" + str;
const i = BigInt(str);
return Number(i >= 0x8000000000000000n ? i - 0x10000000000000000n : i);
}
parseSignedLong("0xffffffffffffffeb"); // -21

Adding Decimal place into number with javascript

I've got this number as a integer 439980
and I'd like to place a decimal place in 2 places from the right. to make it 4399.80
the number of characters can change any time, so i always need it to be 2 decimal places from the right.
how would I go about this?
thanks
function insertDecimal(num) {
return (num / 100).toFixed(2);
}
Just adding that toFixed() will return a string value, so if you need an integer it will require 1 more filter. You can actually just wrap the return value from nnnnnn's function with Number() to get an integer back:
function insertDecimal(num) {
return Number((num / 100).toFixed(2));
}
insertDecimal(99552) //995.52
insertDecimal("501") //5.01
The only issue here is that JS will remove trailing '0's, so 439980 will return 4399.8, rather than 4399.80 as you might hope:
insertDecimal(500); //5
If you're just printing the results then nnnnnn's original version works perfectly!
notes
JavaScript's Number function can result in some very unexpected return values for certain inputs. You can forgo the call to Number and coerce the string value to an integer by using unary operators
return +(num / 100).toFixed(2);
or multiplying by 1 e.g.
return (num / 100).toFixed(2) * 1;
TIL: JavaScript's core math system is kind of weird
Another Method
function makeDecimal(num){
var leftDecimal = num.toString().replace('.', ''),
rightDecimal = '00';
if(leftDecimal.length > 2){
rightDecimal = leftDecimal.slice(-2);
leftDecimal = leftDecimal.slice(0, -2);
}
var n = Number(leftDecimal+'.'+rightDecimal).toFixed(2);
return (n === "NaN") ? num:n
}
makeDecimal(3) // 3.00
makeDecimal(32) // 32.00
makeDecimal(334) // 3.34
makeDecimal(13e+1) // 1.30
Or
function addDecimal(num){
var n = num.toString();
var n = n.split('.');
if(n[1] == undefined){
n[1] = '00';
}
if(n[1].length == 1){
n[1] = n[1]+'0';
}
return n[0]+'.'+n[1];
}
addDecimal(1); // 1.00
addDecimal(11); // 11.00
addDecimal(111); // 111.00
Convert Numbers to money.
function makeMoney(n){
var num = n.toString().replace(/\$|\,/g,'');
if(isNaN(num))
num = "0";
sign = (num == (num = Math.abs(num)));
num = Math.floor(num*100+0.50000000001);
cents = num%100;
num = Math.floor(num/100).toString();
if(cents<10)
cents = "0" + cents;
for (var i = 0; i < Math.floor((num.length-(1+i))/3); i++)
num = num.substring(0,num.length-(4*i+3))+','+num.substring(num.length-(4*i+3));
return (((sign)?'':'-') + '$' + num + '.' + cents);
}
One More.
function addDecimal(n){
return parseFloat(Math.round(n * 100) / 100).toFixed(2);
}

Categories

Resources