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
Related
can anyone come with an idea of how to sort an integer without using an array, and without using string methods as well as sort() method?
for example
input: 642531
output: 123456
I started by writing 2 simple functions - one which checks the length of the number, the other one splits the integer at some point and switches between 2 desired numbers. Below are the 2 functions.
I got stuck with the rest of the solution...
function switchDigits(num, i) { // for input: num=642531, i = 4 returns 624135
let temp = num;
let rest = 0;
for (let j = 0; j < i - 1; j++) {
rest = rest * 10;
rest = rest + temp % 10;
temp = (temp - temp % 10) / 10;
}
let a = temp % 10;
temp = (temp - a) / 10;
let b = temp % 10;
temp = (temp - b) / 10;
temp = Math.pow(10, i - 2) * temp;
temp = temp + 10 * a + b;
temp = Math.pow(10, i - 1) * temp;
temp = temp + rest;
return temp;
}
function checkHowManyDigits(num) { //input: 642534, output: 6 (length of the integer)
let count = 0;
while (num > 0) {
let a = num % 10;
num = (num - a) / 10;
count++;
}
return count;
}
let num = 642534;
let i = checkHowManyDigits(num);
console.log(switchDigits(num));
It actually complicated requirement and so does this answer. It's pure logic and as it is it's a question from a test you should try understanding the logic on your own as a homework.
function checkHowManyDigits(num) { //input: 642534, output: 6 (length of the integer)
let count = 0;
while (num > 0) {
let a = num % 10;
num = (num - a) / 10;
count++;
}
return count;
}
function sortDigit(numOriginal) {
let i = checkHowManyDigits(numOriginal);
let minCount = 0;
let min = 10;
let num = numOriginal;
while (num > 0) {
let d = num % 10;
num = (num - d) / 10;
if (d < min) {
min = d;
minCount = 0;
} else if (d === min) {
minCount++;
}
}
let result = 0;
while (minCount >= 0) {
result += min * Math.pow(10, i - minCount - 1);
minCount--;
}
let newNum = 0;
num = numOriginal;
while (num > 0) {
let d = num % 10;
num = (num - d) / 10;
if (d !== min) {
newNum = newNum * 10 + d;
}
}
if (newNum == 0) return result;
else return result += sortDigit(newNum);
}
console.log(sortDigit(642531));
You could have a look to greater and smaller pairs, like
64
46
The delta is 18, which gets an idea if you compare other pairs, like
71
17
where the delta is 54. Basically any difference of two digits is a multiple of 9.
This in mind, you get a function for taking a single digit out of a number and a single loop who is sorting the digits by using the calculated delta and subtract the value, adjusted by the place.
function sort(number) {
const
getDigit = e => Math.floor(number / 10 ** e) % 10,
l = Math.ceil(Math.log10(number)) - 1;
let e = l;
while (e--) {
const
left = getDigit(e + 1),
right = getDigit(e);
if (left <= right) continue;
number += (right - left) * 9 * 10 ** e;
e = l;
}
return number;
}
console.log(sort(17)); // 17
console.log(sort(71)); // 17
console.log(sort(642531)); // 123456
console.log(sort(987123654)); // 123456789
So eventually I found the best solution.
*This solution is based on a Java solution I found in StackOverFlow forums.
let store = 0;
function getReducedNumbr(number, digit) {
console.log("Remove " + digit + " from " + number);
let newNumber = 0;
let repeateFlag = false;
while (number>0) {
let t = number % 10;
if (t !== digit) {
newNumber = (newNumber * 10) + t;
} else if (t == digit) {
if (repeateFlag) {
console.log(("Repeated min digit " + t + " found. Store is : " + store));
store = (store * 10) + t;
console.log("Repeated min digit " + t + " added to store. Updated store is : " + store);
} else {
repeateFlag = true;
}
}
number = Math.floor(number / 10);
}
console.log("Reduced number is : " + newNumber);
return newNumber;}
function sortNum(num) {
let number = num;
let original = number;
let digit;
while (number > 0) {
digit = number % 10;
console.log("Last digit is : " + digit + " of number : " + number);
temp = Math.floor(number/10);
while (temp > 0) {
console.log("subchunk is " + temp);
t = temp % 10;
if (t < digit) {
digit = t;
}
temp = Math.floor(temp/10);
}
console.log("Smallest digit in " + number + " is " + digit);
store = (store * 10) + digit;
console.log("store is : " + store);
number = getReducedNumbr(number, digit);
}
console.log(("Ascending order of " + original + " is " + store));
return store;
}
console.log(sortNum(4214173));
you can see how it works here https://jsfiddle.net/9dpm14fL/1/
I have Float32Array textures which can be displayed through WebGL correctly. However, when I tried to convert them into Uint16Array, the problem occurs.
Here is my conversion part.
var _floatToHalfFloat = function(input, offset) {
var largestHalf = Math.pow(2, 30-15) * (1 + 1023/1024);
var m = new ArrayBuffer(4);
var n = new Float32Array(m);
var o = new Uint32Array(m);
var f = 0.0;
for (var i = input.length - 1 - offset; i >= 0;i--) {
n[0] = input[i];
f = o[0];
// fast conversion of half
// ref : ftp://www.fox-toolkit.org/pub/fasthalffloatconversion.pdf
if (isNaN(input[i])) {
input[i] = 0x7fff;
} else if(n === Infinity || n > largestHalf) {
input[i] = 0x7c00;
} else if(n === -Infinity || n < -largestHalf) {
input[i] = 0xfc00;
} else if(n === 0) {
input[i] = 0;
} else {
input[i] = ((f>>16)&0x8000)|((((f&0x7f800000)-0x38000000)>>13)&0x7c00)|((f>>13)&0x03ff);
}
}
return new Uint16Array(input);
};
We can see saturated colors (full red, green and/or blue) in the converted image when reaching black color in the original image. I think the function doesn't work very well near 0.
I have done a quick implementation of wikipedia explanation of norm of the float 16 bits.
<html>
<head>
<script>
var _floatToHalfFloat = #### YOUR FUNCTION HERE CUT ####
var _halfFloatToFloat = function(hf) {
var m = new ArrayBuffer(2);
var n = new Uint16Array(m);
n[0] = hf;
var sign = n[0] & 0x8000;
var exp = (n[0] >> 10) & 0x1F;
var mant = n[0]& 0x03FF;
document.getElementById('sign').innerHTML += sign+" - ";
document.getElementById('exp').innerHTML += exp+" - ";
document.getElementById('mant').innerHTML += mant+" - ";
if (exp == 0x1F) {
return 1.0 * Math.pow(-1, sign) * Infinity;
} else if (exp == 0) {
return Math.pow(-1, sign) *
Math.pow(2, -14) *
(mant / Math.pow(2, 10));
} else {
return Math.pow(-1, sign) *
Math.pow(2, exp-15) *
(1+(mant / Math.pow(2, 10)));
}
};
document.addEventListener("DOMContentLoaded", function(event) {
var input = new Float32Array(8);
input[0] = 2.5;
input[1] = 0.25;
input[2] = 0.025;
input[3] = 0.025;
input[4] = 0.0025;
input[5] = 0.00025;
input[6] = 0.000025;
input[7] = 0.0;
var i, s = "Value before = ";
for (i = 0; i < input.length; i++)
s += input[i] + " - ";
document.getElementById('res1').innerHTML = s;
var output = _floatToHalfFloat(input, 0);
s = "Value after = ";
for (i = 0; i < output.length; i++)
s += _halfFloatToFloat(output[i]) + " - ";
document.getElementById('res2').innerHTML = s;
});
</script>
</head>
<body>
<span id="res1">result</span></br>
<span id="res2">result</span></br>
</br></br></br>
<span id="sign">signs =</span></br>
<span id="exp">exponents =</span></br>
<span id="mant">mantissas =</span></br>
</body>
</html>
The test results are shown below :
Value before = 2.5 - 0.25 - 0.02500000037252903 - 0.02500000037252903 - 0.0024999999441206455 - 0.0002500000118743628 - 0.00002499999936844688 - 0 -
Value after = 2.5 - 0.25 - 0.024993896484375 - 0.024993896484375 - 0.002498626708984375 - 0.0002498626708984375 - Infinity - 2 -
signs =0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 -
exponents =16 - 13 - 9 - 9 - 6 - 3 - 31 - 16 -
mantissas =256 - 0 - 614 - 614 - 286 - 24 - 653 - 0 -
This shows that the 2 last information are not coherent. 0.000025 is transformed into Infinity (rather than 0?) and 0 itself is transformed to 2. This doesn't appear to be correct. When you want to code a zero "wikipedia says" your mantissa AND your exponent should be zero. In the code you provided the mantissa is zero but the exponent is 16 which leads to 2 (2^(16-15)).
After tweaking a bit your function it appears that all cases are treated as normal one. This is due to a bug in your if statements. So instead of having :
} else if(n === 0) {
input[i] = 0;
}
You want probably do something like that :
} else if(n[0] === 0) {
input[i] = 0;
}
And the same for all uses of n variable. But you still have the underflow problem.So may be you can find acceptable to do :
} else if(Math.abs(n[0]) < 0.0001) {
input[i] = 0;
}
I'm using Angular "currency" filter to show price in a shopping cart. The prices are fetched from a back end server. So sometimes the price may not be available to show to the user. In that case I just want to show the user that the price is not available in the same field as of currency field. I can not show plain text in a currency filter. The only solution I found is to keep another text field to show/hide when a price is not available.But this is some what unnecessary I think. Is there any way to extend or override the built in "currency" filter of Angular js ?. Kindly appreciate some help.
<div class="large-12 medium-12 small-12 columns pad-none nzs-pro-list-item-price">
{{item.ItmPrice|currency}}
</div>
Create your custom filter which will internally use currency when value is present, otherwise it will return text which you want to show instead.
Markup
{{amount | customFormat:"USD$": "N/A"}}
Filter
.filter('customFormat', function($filter) {
return function(value, format, text) {
if (angular.isDefined(value) && value != null)
return $filter('currency')(value, format);
else
return text;
}
});
Working Plunkr
I feel the best way is to rewrite currency filter, so that you have fill control over Pattern, Grouping Separator, Decimal Separator & symbol position
<span>
{{26666662.5226 | fmtCurrency :"##.###,###" : "." : "," : "$" : "first"}}
</span>
Resluts in: $26.666.662,523
Filter:
app.filter("fmtCurrency", ['CurrencyService', function sasCurrency(CurrencyService) {
return function (amount, pattern, groupingSeparator, decimalSeparator, currencySymbol, symbolPosition) {
var patternInfo = CurrencyService.parsePattern(pattern, groupingSeparator, decimalSeparator);
var formattedCurrency = CurrencyService.formatCurrency(amount, patternInfo, groupingSeparator, decimalSeparator);
if (symbolPosition === 'last')
return formattedCurrency + currencySymbol;
else
return currencySymbol + formattedCurrency;
};
}])
Service: formatNumber which is the same function used in angular currency filter is being used here inside service
app.service("CurrencyService", function () {
var PATTERN_SEP = ';',
DECIMAL_SEP = '.',
GROUP_SEP = ',',
ZERO = '0',
DIGIT = "#";
var MAX_DIGITS = 22;
var ZERO_CHAR = '0';
return {
parsePattern: function (pattern, groupingSeparator, decimalSeparator) {
return parsePattern(pattern, groupingSeparator, decimalSeparator);
},
formatCurrency: function (amount, patternInfo, groupingSeparator, decimalSeparator) {
return formatNumber(amount, patternInfo, groupingSeparator, decimalSeparator);
}
}
/*
* Currency formatter utility
*/
function isUndefined(value) { return typeof value === 'undefined'; }
/**
* main function for parser
* #param str {string} pattern to be parsed (e.g. #,##0.###).
*/
function parsePattern(pattern, groupSep, decimalSep) {
DECIMAL_SEP = decimalSep;
GROUP_SEP = groupSep;
var p = {
minInt: 1,
minFrac: 0,
maxFrac: 0,
posPre: '',
posSuf: '',
negPre: '',
negSuf: '',
gSize: 0,
lgSize: 0
};
var ZERO = '0',
DIGIT = "#";
var parts = pattern.split(PATTERN_SEP),
positive = parts[0],
negative = parts[1];
var parts = positive.split(DECIMAL_SEP),
integer = parts[0],
fraction = parts[1];
console.log(parts);
p.posPre = integer.substr(0, integer.indexOf(DIGIT));
if (fraction) {
for (var i = 0; i < fraction.length; i++) {
var ch = fraction.charAt(i);
console.log(ch, ZERO, DIGIT);
if (ch == ZERO)
p.minFrac = p.maxFrac = i + 1;
else if (ch == DIGIT)
p.maxFrac = i + 1;
else
p.posSuf += ch;
}
}
var groups = integer.split(GROUP_SEP);
p.gSize = groups[1] ? groups[1].length : 0;
p.lgSize = (groups[2] || groups[1]) ? (groups[2] || groups[1]).length : 0;
if (negative) {
var trunkLen = positive.length - p.posPre.length - p.posSuf.length,
pos = negative.indexOf(DIGIT);
p.negPre = negative.substr(0, pos).replace(/\'/g, '');
p.negSuf = negative.substr(pos + trunkLen).replace(/\'/g, '');
} else {
// hardcoded '-' sign is fine as all locale use '-' as MINUS_SIGN. (\u2212 is the same as '-')
p.negPre = '-' + p.posPre;
p.negSuf = p.posSuf;
}
return p;
}
function isString(value) { return typeof value === 'string'; }
function isNumber(value) { return typeof value === 'number'; }
/**
* Format a number into a string
* #param {number} number The number to format
* #param {{
* minFrac, // the minimum number of digits required in the fraction part of the number
* maxFrac, // the maximum number of digits required in the fraction part of the number
* gSize, // number of digits in each group of separated digits
* lgSize, // number of digits in the last group of digits before the decimal separator
* negPre, // the string to go in front of a negative number (e.g. `-` or `(`))
* posPre, // the string to go in front of a positive number
* negSuf, // the string to go after a negative number (e.g. `)`)
* posSuf // the string to go after a positive number
* }} pattern
* #param {string} groupSep The string to separate groups of number (e.g. `,`)
* #param {string} decimalSep The string to act as the decimal separator (e.g. `.`)
* #param {[type]} fractionSize The size of the fractional part of the number
* #return {string} The number formatted as a string
*/
function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
if (!(isString(number) || isNumber(number)) || isNaN(number)) return '';
var isInfinity = !isFinite(number);
var isZero = false;
var numStr = Math.abs(number) + '',
formattedText = '',
parsedNumber;
if (isInfinity) {
formattedText = '\u221e';
} else {
parsedNumber = parse(numStr, '.');
roundNumber(parsedNumber, fractionSize, pattern.minFrac, pattern.maxFrac);
var digits = parsedNumber.d;
var integerLen = parsedNumber.i;
var exponent = parsedNumber.e;
var decimals = [];
isZero = digits.reduce(function (isZero, d) { return isZero && !d; }, true);
// pad zeros for small numbers
while (integerLen < 0) {
digits.unshift(0);
integerLen++;
}
// extract decimals digits
if (integerLen > 0) {
decimals = digits.splice(integerLen, digits.length);
} else {
decimals = digits;
digits = [0];
}
// format the integer digits with grouping separators
var groups = [];
if (digits.length >= pattern.lgSize) {
groups.unshift(digits.splice(-pattern.lgSize, digits.length).join(''));
}
while (digits.length > pattern.gSize) {
groups.unshift(digits.splice(-pattern.gSize, digits.length).join(''));
}
if (digits.length) {
groups.unshift(digits.join(''));
}
formattedText = groups.join(groupSep);
// append the decimal digits
if (decimals.length) {
formattedText += decimalSep + decimals.join('');
}
if (exponent) {
formattedText += 'e+' + exponent;
}
}
if (number < 0 && !isZero) {
return pattern.negPre + formattedText + pattern.negSuf;
} else {
return pattern.posPre + formattedText + pattern.posSuf;
}
}
function parse(numStr, decimalSep) {
var exponent = 0, digits, numberOfIntegerDigits;
var i, j, zeros;
DECIMAL_SEP = decimalSep;
// Decimal point?
if ((numberOfIntegerDigits = numStr.indexOf(DECIMAL_SEP)) > -1) {
numStr = numStr.replace(DECIMAL_SEP, '');
}
// Exponential form?
if ((i = numStr.search(/e/i)) > 0) {
// Work out the exponent.
if (numberOfIntegerDigits < 0) numberOfIntegerDigits = i;
numberOfIntegerDigits += +numStr.slice(i + 1);
numStr = numStr.substring(0, i);
} else if (numberOfIntegerDigits < 0) {
// There was no decimal point or exponent so it is an integer.
numberOfIntegerDigits = numStr.length;
}
// Count the number of leading zeros.
for (i = 0; numStr.charAt(i) === ZERO_CHAR; i++) {/* jshint noempty: false */ }
if (i === (zeros = numStr.length)) {
// The digits are all zero.
digits = [0];
numberOfIntegerDigits = 1;
} else {
// Count the number of trailing zeros
zeros--;
while (numStr.charAt(zeros) === ZERO_CHAR) zeros--;
// Trailing zeros are insignificant so ignore them
numberOfIntegerDigits -= i;
digits = [];
// Convert string to array of digits without leading/trailing zeros.
for (j = 0; i <= zeros; i++ , j++) {
digits[j] = +numStr.charAt(i);
}
}
// If the number overflows the maximum allowed digits then use an exponent.
if (numberOfIntegerDigits > MAX_DIGITS) {
digits = digits.splice(0, MAX_DIGITS - 1);
exponent = numberOfIntegerDigits - 1;
numberOfIntegerDigits = 1;
}
return { d: digits, e: exponent, i: numberOfIntegerDigits };
}
/**
* Round the parsed number to the specified number of decimal places
* This function changed the parsedNumber in-place
*/
function roundNumber(parsedNumber, fractionSize, minFrac, maxFrac) {
var digits = parsedNumber.d;
var fractionLen = digits.length - parsedNumber.i;
// determine fractionSize if it is not specified; `+fractionSize` converts it to a number
fractionSize = (isUndefined(fractionSize)) ? Math.min(Math.max(minFrac, fractionLen), maxFrac) : +fractionSize;
// The index of the digit to where rounding is to occur
var roundAt = fractionSize + parsedNumber.i;
var digit = digits[roundAt];
if (roundAt > 0) {
// Drop fractional digits beyond `roundAt`
digits.splice(Math.max(parsedNumber.i, roundAt));
// Set non-fractional digits beyond `roundAt` to 0
for (var j = roundAt; j < digits.length; j++) {
digits[j] = 0;
}
} else {
// We rounded to zero so reset the parsedNumber
fractionLen = Math.max(0, fractionLen);
parsedNumber.i = 1;
digits.length = Math.max(1, roundAt = fractionSize + 1);
digits[0] = 0;
for (var i = 1; i < roundAt; i++) digits[i] = 0;
}
if (digit >= 5) {
if (roundAt - 1 < 0) {
for (var k = 0; k > roundAt; k--) {
digits.unshift(0);
parsedNumber.i++;
}
digits.unshift(1);
parsedNumber.i++;
} else {
digits[roundAt - 1]++;
}
}
// Pad out with zeros to get the required fraction length
for (; fractionLen < Math.max(0, fractionSize); fractionLen++) digits.push(0);
// Do any carrying, e.g. a digit was rounded up to 10
var carry = digits.reduceRight(function (carry, d, i, digits) {
d = d + carry;
digits[i] = d % 10;
return Math.floor(d / 10);
}, 0);
if (carry) {
digits.unshift(carry);
parsedNumber.i++;
}
}
})
$provide.decorator('currencyFilter', ['$delegate',
function ($delegate) {
var crncyFilter = $delegate;
var extendsFilter = function () {
var res = crncyFilter.apply(this, arguments);
if (arguments[2]) {
var digi1 = arguments[2] || 2;
return arguments[1] + Number(arguments[0]).toFixed(digi1);
}
else {
if (arguments[1] == "¥") {
return arguments[1] + Number(arguments[0]).toFixed(1);
}
}
};
return extendsFilter;
}]);
This is the way to Override Decimal digit
I need to a function to convert an integer to the equivalent alpha ordered list index. For example:
1 = a
2 = b
.
.
.
26 = z
27 = aa
28 = ab
.
.
etc.
Currently I have the following which almost works but there's a small logic error somewhere that makes it not quite get it right (it goes ax, ay, bz, ba, bb, bc...):
function intToAlpha( int ) {
var asciiStart = 97,
alphaMax = 26,
asciiCode,
char,
alpha = '',
place,
num,
i;
for ( i = 0; Math.pow(alphaMax, i) < int; i++ ) {
place = Math.pow(alphaMax, i);
num = Math.floor( ( int / place ) % alphaMax);
asciiCode = ( num == 0 ? alphaMax : num ) + asciiStart - 1;
char = String.fromCharCode(asciiCode);
alpha = char + alpha;
}
return alpha;
}
for (i = 1; i < 300; i++) {
console.log( i + ': ' + intToAlpha(i) );
}
This function is used in NVu/Kompozer/SeaMonkey Composer, with a small tweak to generate lower case directly:
function ConvertArabicToLetters(num)
{
var letters = "";
while (num > 0) {
num--;
letters = String.fromCharCode(97 + (num % 26)) + letters;
num = Math.floor(num / 26);
}
return letters;
}
You need to make sure that you use the correct value when taking the mod.
function intToAlpha( int ) {
var asciiStart = 97,
alphaMax = 26,
asciiCode,
char,
alpha = "";
while(int > 0) {
char = String.fromCharCode(asciiStart + ((int-1) % alphaMax));
alpha = char + alpha;
int = Math.floor((int-1)/26);
}
return alpha;
}
A while back I needed the same thing in SQL, so I asked (and answered) the question Multi-base conversion - using all combinations for URL shortener.
The thing that is making it complicated is that it's not a straight base conversion, as there is no character representing the zero digit.
I converted the SQL function into Javascript:
function tinyEncode(id) {
var code, value, adder;
var chars = 'abcdefghijklmnopqrstuvwxyz';
if (id <= chars.length) {
code = chars.substr(id - 1, 1);
} else {
id--;
value = chars.length;
adder = 0;
while (id >= value * (chars.length + 1) + adder) {
adder += value;
value *= chars.length;
}
code = chars.substr(Math.floor((id - adder) / value) - 1, 1);
id = (id - adder) % value;
while (value > 1) {
value = Math.floor(value / chars.length);
code += chars.substr(Math.floor(id / value), 1);
id = id % value;
}
}
return code;
}
Demo: http://jsfiddle.net/Guffa/mstBe/
What's the easiest way to convert a floating point number to its binary representation in Javascript? (e.g. 1.0 -> 0x3F800000).
I have tried to do it manually, and this works to some extent (with usual numbers), but it fails for very big or very small numbers (no range checking) and for special cases (NaN, infinity, etc.):
function floatToNumber(flt)
{
var sign = (flt < 0) ? 1 : 0;
flt = Math.abs(flt);
var exponent = Math.floor(Math.log(flt) / Math.LN2);
var mantissa = flt / Math.pow(2, exponent);
return (sign << 31) | ((exponent + 127) << 23) | ((mantissa * Math.pow(2, 23)) & 0x7FFFFF);
}
Am I reinventing the wheel?
EDIT: I've improved my version, now it handles special cases.
function assembleFloat(sign, exponent, mantissa)
{
return (sign << 31) | (exponent << 23) | (mantissa);
}
function floatToNumber(flt)
{
if (isNaN(flt)) // Special case: NaN
return assembleFloat(0, 0xFF, 0x1337); // Mantissa is nonzero for NaN
var sign = (flt < 0) ? 1 : 0;
flt = Math.abs(flt);
if (flt == 0.0) // Special case: +-0
return assembleFloat(sign, 0, 0);
var exponent = Math.floor(Math.log(flt) / Math.LN2);
if (exponent > 127 || exponent < -126) // Special case: +-Infinity (and huge numbers)
return assembleFloat(sign, 0xFF, 0); // Mantissa is zero for +-Infinity
var mantissa = flt / Math.pow(2, exponent);
return assembleFloat(sign, exponent + 127, (mantissa * Math.pow(2, 23)) & 0x7FFFFF);
}
I'm still not sure if this works 100% correctly, but it seems to work good enough.
(I'm still looking for existing implementations).
new technologies are making this easy and probably also more forward-compatible. I love extending built in prototypes, not everyone does. So feel free to modify following code to classical procedural approach:
(function() {
function NumberToArrayBuffer() {
// Create 1 entry long Float64 array
return [new Float64Array([this]).buffer];
}
function NumberFromArrayBuffer(buffer) {
// Off course, the buffer must be at least 8 bytes long, otherwise this is a parse error
return new Float64Array(buffer, 0, 1)[0];
}
if(Number.prototype.toArrayBuffer) {
console.warn("Overriding existing Number.prototype.toArrayBuffer - this can mean framework conflict, new WEB API conflict or double inclusion.");
}
Number.prototype.toArrayBuffer = NumberToArrayBuffer;
Number.prototype.fromArrayBuffer = NumberFromArrayBuffer;
// Hide this methods from for-in loops
Object.defineProperty(Number.prototype, "toArrayBuffer", {enumerable: false});
Object.defineProperty(Number.prototype, "fromArrayBuffer", {enumerable: false});
})();
Test:
(function() {
function NumberToArrayBuffer() {
// Create 1 entry long Float64 array
return new Float64Array([this.valueOf()]).buffer;
}
function NumberFromArrayBuffer(buffer) {
// Off course, the buffer must be ar least 8 bytes long, otherwise this is a parse error
return new Float64Array(buffer, 0, 1)[0];
}
if(Number.prototype.toArrayBuffer) {
console.warn("Overriding existing Number.prototype.toArrayBuffer - this can mean framework conflict, new WEB API conflict or double inclusion.");
}
Number.prototype.toArrayBuffer = NumberToArrayBuffer;
Number.fromArrayBuffer = NumberFromArrayBuffer;
// Hide this methods from for-in loops
Object.defineProperty(Number.prototype, "toArrayBuffer", {enumerable: false});
Object.defineProperty(Number, "fromArrayBuffer", {enumerable: false});
})();
var test_numbers = [0.00000001, 666666666666, NaN, Infinity, -Infinity,0,-0];
console.log("Conversion symethry test: ");
test_numbers.forEach(
function(num) {
console.log(" ", Number.fromArrayBuffer((num).toArrayBuffer()));
}
);
console.log("Individual bytes of a Number: ",new Uint8Array((666).toArrayBuffer(),0,8));
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>
Here's a function that works on everything I've tested it on, except it doesn't distinguish -0.0 and +0.0.
It's based on code from http://jsfromhell.com/classes/binary-parser, but it's specialized for 32-bit floats and returns an integer instead of a string. I also modified it to make it faster and (slightly) more readable.
// Based on code from Jonas Raoni Soares Silva
// http://jsfromhell.com/classes/binary-parser
function encodeFloat(number) {
var n = +number,
status = (n !== n) || n == -Infinity || n == +Infinity ? n : 0,
exp = 0,
len = 281, // 2 * 127 + 1 + 23 + 3,
bin = new Array(len),
signal = (n = status !== 0 ? 0 : n) < 0,
n = Math.abs(n),
intPart = Math.floor(n),
floatPart = n - intPart,
i, lastBit, rounded, j, exponent;
if (status !== 0) {
if (n !== n) {
return 0x7fc00000;
}
if (n === Infinity) {
return 0x7f800000;
}
if (n === -Infinity) {
return 0xff800000
}
}
i = len;
while (i) {
bin[--i] = 0;
}
i = 129;
while (intPart && i) {
bin[--i] = intPart % 2;
intPart = Math.floor(intPart / 2);
}
i = 128;
while (floatPart > 0 && i) {
(bin[++i] = ((floatPart *= 2) >= 1) - 0) && --floatPart;
}
i = -1;
while (++i < len && !bin[i]);
if (bin[(lastBit = 22 + (i = (exp = 128 - i) >= -126 && exp <= 127 ? i + 1 : 128 - (exp = -127))) + 1]) {
if (!(rounded = bin[lastBit])) {
j = lastBit + 2;
while (!rounded && j < len) {
rounded = bin[j++];
}
}
j = lastBit + 1;
while (rounded && --j >= 0) {
(bin[j] = !bin[j] - 0) && (rounded = 0);
}
}
i = i - 2 < 0 ? -1 : i - 3;
while(++i < len && !bin[i]);
(exp = 128 - i) >= -126 && exp <= 127 ? ++i : exp < -126 && (i = 255, exp = -127);
(intPart || status !== 0) && (exp = 128, i = 129, status == -Infinity ? signal = 1 : (status !== status) && (bin[i] = 1));
n = Math.abs(exp + 127);
exponent = 0;
j = 0;
while (j < 8) {
exponent += (n % 2) << j;
n >>= 1;
j++;
}
var mantissa = 0;
n = i + 23;
for (; i < n; i++) {
mantissa = (mantissa << 1) + bin[i];
}
return ((signal ? 0x80000000 : 0) + (exponent << 23) + mantissa) | 0;
}