Strange method result using Math.round - javascript

When this method is called with
knownScore = 70,
newScore = 70,
depth = 1,
it returns 3535 !!!!!
How is this possible?
this.weightedAvg = function(depth, knownScore, newScore) {
if ((knownScore > 100) || (knownScore < -100)) return newScore;
else return Math.round((depth*knownScore + newScore)/(depth + 1));
};
When called with values 35, 70, 2, it returns 2357!
Any help please?

The value of newScore you're passing to the function is a string. You should make sure they are all numbers. This code will work (notice the + sign that converts newScore to a number):
this.weightedAvg = function(depth, knownScore, newScore) {
if ((knownScore > 100) || (knownScore < -100)) return newScore;
else return Math.round((depth*knownScore + +newScore)/(depth + 1));
};
More details:
70 + '70' // this is string concatenation instead of addition, results in 7070
The result is converted to a number when it is divided by 2:
'7070'/2 // converts to number, resulting in 3535

You need to parse your var to number like this:
var number1 = Number(n);
You are passing string so he do "2" + "35" + "70" instead of 2 + 35 + 70 !

Related

why javascript show string all arithmetic operation?

as you show below, when javascript doing an arithmetic operation all value concatenation with the string it shows a string value but I have some confusion...
var x = 10;
var y = 20;
var sum = x + y;
console.log("sum is :" + sum); //this is number
But confusion is
var x = 10;
var y = 20;
console.log("sum is : " + 10 + 20 ); //why this is string
var x = 10;
var y = "The value is " + x; // why this is string
var x = 10;
var y = 20;
var sum = x + y;
var z = 'sum is' + sum; //why this string
console.log("sum is : " + sum) // why this is not string coz it is also concatenation with string.
JavaScript will concatenate and coerce in a certain order of operations. You can add parentheses to add numbers before coercing to a string.
console.log("sum is : " + 10 + 20); // sum is : 1020
console.log("sum is : " + (10 + 20)); // sum is : 30
The unary + operator can be used to convert a variable to a number:
var y = "5"; // y is a string
var x = + y; // x is a number
If the variable cannot be converted, it will still become a number, but with the value NaN (Not a Number):
var y = "John"; // y is a string
var x = + y; // x is a number (NaN)
When JavaScript tries to operate on a "wrong" data type, it will try to convert the value to a "right" type.
5 + null // returns 5 because null is converted to 0
"5" + null // returns "5null" because null is converted to "null"
"5" + 2 // returns "52" because 2 is converted to "2"
"5" - 2 // returns 3 because "5" is converted to 5
"5" * "2" // returns 10 because "5" and "2" are converted to 5 and 2
So if you put numbers inside parenthesis like (10 + 20) then it will perform arithmetic operation first then it will do the concatenation outside. If either one of them would be string then it would do the concatenation inside as well.
var console.log("sum is : " + (10 + 20) ); // sum is : 30
var console.log("sum is : " + (10 + '20') ); // sum is : 1020
When you are adding a number with a string it counts the number as a string, like console.log("sum is : " + 10 + 20 ).
But when 10 and 20 is under a variable it counts the number as a variable value.
If you want to use numbers with a string use "sum is: " + parseInt(10) like this.

javascript indexOf not working as expected with array

I am getting -1 from myarray.indexOf(element) even when element appears to be in myarray.
Here's some code snippets:
function createChangeRecord( old_array, new_array ) {
var nds = new_array.slice(0,new_array.length);
var el, idx;
if (...) {
...
} else if ( old_array.length==new_array.length ) {
for ( var i=0; i<old_array.length; i++ ) {
el = old_array[i];
idx = nds.indexOf(el);
if ( idx!=(-1) ) {
...
} else {
var a = "el: " + el + "; nds: " + nds + "; nds.indexOf(el): " + nds.indexOf(el);
alert( a );
...
}
}
...
}
...
}
The alert shows me that nds does indeed contain el but the alert should only fire when idx==-1, which should only be true when nds does not contain el.
I know I haven't given enough information to determine the specific issue in my case, but maybe someone can tell me some general reasons which might cause this behavior?
Responses to a similar question suggested using jQuery inArray() instead of indexOf, but I want to know why indexOf doesn't work. Others suggested that indexOf is for strings, not arrays, but that's not true from the online docs I can find.
Use
nds.indexOf(parseInt(el,10))
where nds is an array and el is a number (or supposed to be a number)
Edit:
From msdn:
JavaScript is a loosely typed language, which means you do not declare
the data types of variables explicitly. In many cases JavaScript
performs conversions automatically when they are needed. For example,
if you add a number to an item that consists of text (a string), the
number is converted to text.
And I guess such conversion was the reason of indexOf returning -1 because one of your array contained number and other contained string.
For example:
old_array = ["10", "20", "30"];
new_array = [10, 20, 30];
Below is my attempt to answer your questions:
Why indexOf() does not work?
It does work and I guess it worked in your case too.
It returned -1 when el string, e.g "100", was not found in an array of numbers, e.g. nds=[100,200] which is true. Because "100" string is not same as 100 number.
Does indexOf() work with strings, array, etc?
Yes, indexOf() works with array (of number, string, or any object), as well as with string. But you have to make sure to check with same types.
What does parseInt() do?
To avoid unintended comparison of a number with a string, we can use parseInt(), for example parseInt("123", 10) returns the number 123.
The second argument 10 is called radix. A number (from 2 to 36) that represents the numeral system to be used.
Summary:
> "javascript is awesome".indexOf('v')
2
> [10, 20, 30].indexOf("20")
-1
> [10, 20, 30].indexOf(20)
1
> [10, 20, 30].indexOf( parseInt("20", 10) )
1
> typeof (100)
number
> typeof ("100")
string
> typeof( parseInt( "100", 10))
number
> parseInt( "100", 10)
100
> parseInt("100", 2)
4
> parseInt(11.3, 10)
11
> parseInt(11.3, 2)
3
> [10.3, 11.3, 12.3, 11].indexOf( parseInt(11.3, 10) )
3
To see all of above in action:
check the below code snippet but be aware of alert(); and console.log(); when you run it.
function createChangeRecord( old_array, new_array ) {
var nds = new_array.slice( 0, new_array.length ); // this seems to be redundant
var el, idx, msg;
if ( old_array.length == new_array.length ) {
for ( var i=0; i<old_array.length; i++ ) {
el = old_array[i];
idx = nds.indexOf(el);
if ( idx != -1 ) {
msg = "Found: el: " + el + "; nds: " + nds + "; nds.indexOf(el): " + idx + "\n typeof el: " + (typeof el) + "; typepf nds[" + i + "]: " + (typeof nds[i]);
} else {
msg = "Not Found: el: " + el + "; nds: " + nds + "; nds.indexOf(el): " + idx + "\n typeof el: " + (typeof el) + "; typepf nds[" + i + "]: " + (typeof nds[i]);
}
console.log( msg );
alert( msg );
}
}
else {
var err = 'Array lengths are not same';
console.log( err );
alert( err );
}
}
// this will work
var old_array_g = [ 10, 20 ];
var new_array_g = [ 10, 20 ];
createChangeRecord( old_array_g, new_array_g );
// this will not work
var old_array_g = [ "10", "20" ];
var new_array_g = [ 10, 20 ];
createChangeRecord( old_array_g, new_array_g );
// Yes: indesOf works with strings too
var withStrings = "'javascript is awesome'.indexOf('v'): " + "javascript is awesome".indexOf('v');
console.log( withStrings );
alert( withStrings );
// parseInt() returns a number or say integer
var usingParse = "typeof(123): " + typeof( 123 ) + "; typeof( parseInt('123', 10) ): " + typeof ( parseInt('123', 10) ) + "; typeof ('123'): " + typeof('123');
console.log( usingParse );
alert( usingParse );
// parseInt() with base 2
var parseBase2 = "parseInt( '100', 2 ): " + parseInt('100', 2) + "; parseInt( '100' , 10): " + parseInt('100', 10);
console.log( parseBase2 );
alert( parseBase2 );
indexOf does work and does do what you say it does.
For example (to demonstrate from a console):
> a = [1,2,3,4,5,6,7,8];
[1, 2, 3, 4, 5, 6, 7, 8]
> b = a.slice(0,a.length);
[1, 2, 3, 4, 5, 6, 7, 8]
> b.indexOf(a[4])
4
If you're getting this error, it might mean you've mixed up source and destination (the array before the dot is the one being searched), or you have another subtle programming error (like you aren't comparing the array you think you're comparing).
When you use indexOf(value) on an Array, it returns you the index of the value in the array.
> var testArray = ["a","b","c"];
> testArray.indexOf(1)
-1
> testArray.indexOf("b")
1
> testArray.indexOf("c")
2
> testArray = [10,12,3];
> testArray.indexOf(12)
1
You should check what you get from el with a typeof(el)
Taking the top example:
where you have idx=nds.indexOf(el)
replace it with idx=nds.indexOf(''+el+'')
It solved a similar problem for me within the thing I'm working on, but I stumbled on it messing around looking for a solution.
Whether it's stable in all circumstances is something I can't answer.
If your search array contained numbers, and you want to search for items like 2 or "2"
nds = [1, 2, 3, 4, 5];
This works (Add plus)
nds.indexOf(+el)

Why I got NaN in this javaScript code?

First I test that every variable got a number value:
09-11 18:15:00.420:
d_drop: -1.178791867393647
drop_at_zero: 0.0731037475605623
sightHeight: 4.5
d_distance: 40
zeroRange: 10
09-11 18:15:00.420:
d_drop: true
drop_at_zero: true
sightHeight: true
d_distance: true
zeroRange: true
function isNumber (o) {
return ! isNaN (o-0) && o != null;
}
var d_drop; // in calculation this gets value 1.1789
var d_path = -d_drop - sightHeight + (drop_at_zero + sightHeight) * d_distance / zeroRange;
console.log("Path: " + d_path + " cm");
and in the log:
09-11 18:15:00.430: D/CordovaLog(1533): Path: NaN cm
WHY? I have tried to figure that out couple of hours now and no success, maybe someone has an idea, I haven't!
Thanks!
Sami
-------ANSWER IS that parse every variable when using + operand-----------
var d_path = parseFloat(-d_drop) - parseFloat(sightHeight) + (parseFloat(drop_at_zero) + parseFloat(sightHeight)) * parseFloat(d_distance) / parseFloat(zeroRange);
The addition operator + will cast things as strings if either operand is a string. You need to parse ALL of your inputs (d_drop, sightHeight, etc) as numbers before working with them.
Here's a demo of how the + overload works. Notice how the subtraction operator - is not overloaded and will always cast the operands to numbers:
var numberA = 1;
var numberB = 2;
var stringA = '3';
var stringB = '4';
numberA + numberB // 3 (number)
numberA - numberB // -1 (number)
stringA + stringB // "34" (string)
stringA - stringB // -1 (number)
numberA + stringB // "14" (string)
numberA - stringB // -3 (number)
http://jsfiddle.net/jbabey/abwhd/
At least one of your numbers is a string. sightHeight is the most likely culprit, as it would concatenate with drop_at_zero to produce a "number" with two decimal points - such a "number" is not a number, hence NaN.
Solution: use parseFloat(varname) to convert to numbers.
If you're using -d_drop as a variable name, that is probably the culprit. Variables must start with a letter.
var d_drop = -1.178791867393647,
drop_at_zero = 0.0731037475605623,
sightHeight = 4.5,
d_distance = 40,
zeroRange = 10;
var d_path = d_drop - sightHeight + (drop_at_zero + sightHeight) * d_distance / zeroRange;
console.log("Path: " + d_path + " cm"); // outputs: Path: 12.613623122848603 cm

Javascript: How to retrieve the number of decimals of a *string* number?

I have a set of string numbers having decimals, for example: 23.456, 9.450, 123.01... I need to retrieve the number of decimals for each number, knowing that they have at least 1 decimal.
In other words, the retr_dec() method should return the following:
retr_dec("23.456") -> 3
retr_dec("9.450") -> 3
retr_dec("123.01") -> 2
Trailing zeros do count as a decimal in this case, unlike in this related question.
Is there an easy/delivered method to achieve this in Javascript or should I compute the decimal point position and compute the difference with the string length? Thanks
function decimalPlaces(num) {
var match = (''+num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
if (!match) { return 0; }
return Math.max(
0,
// Number of digits right of decimal point.
(match[1] ? match[1].length : 0)
// Adjust for scientific notation.
- (match[2] ? +match[2] : 0));
}
The extra complexity is to handle scientific notation so
decimalPlaces('.05')
2
decimalPlaces('.5')
1
decimalPlaces('1')
0
decimalPlaces('25e-100')
100
decimalPlaces('2.5e-99')
100
decimalPlaces('.5e1')
0
decimalPlaces('.25e1')
1
function retr_dec(num) {
return (num.split('.')[1] || []).length;
}
function retr_dec(numStr) {
var pieces = numStr.split(".");
return pieces[1].length;
}
Since there is not already a regex-based answer:
/\d*$/.exec(strNum)[0].length
Note that this "fails" for integers, but per the problem specification they will never occur.
You could get the length of the decimal part of your number this way:
var value = 192.123123;
stringValue = value.toString();
length = stringValue.split('.')[1].length;
It makes the number a string, splits the string in two (at the decimal point) and returns the length of the second element of the array returned by the split operation and stores it in the 'length' variable.
Try using String.prototype.match() with RegExp /\..*/ , return .length of matched string -1
function retr_decs(args) {
return /\./.test(args) && args.match(/\..*/)[0].length - 1 || "no decimal found"
}
console.log(
retr_decs("23.456") // 3
, retr_decs("9.450") // 3
, retr_decs("123.01") // 2
, retr_decs("123") // "no decimal found"
)
I had to deal with very small numbers so I created a version that can handle numbers like 1e-7.
Number.prototype.getPrecision = function() {
var v = this.valueOf();
if (Math.floor(v) === v) return 0;
var str = this.toString();
var ep = str.split("e-");
if (ep.length > 1) {
var np = Number(ep[0]);
return np.getPrecision() + Number(ep[1]);
}
var dp = str.split(".");
if (dp.length > 1) {
return dp[1].length;
}
return 0;
}
document.write("NaN => " + Number("NaN").getPrecision() + "<br>");
document.write("void => " + Number("").getPrecision() + "<br>");
document.write("12.1234 => " + Number("12.1234").getPrecision() + "<br>");
document.write("1212 => " + Number("1212").getPrecision() + "<br>");
document.write("0.0000001 => " + Number("0.0000001").getPrecision() + "<br>");
document.write("1.12e-23 => " + Number("1.12e-23").getPrecision() + "<br>");
document.write("1.12e8 => " + Number("1.12e8").getPrecision() + "<br>");
A slight modification of the currently accepted answer, this adds to the Number prototype, thereby allowing all number variables to execute this method:
if (!Number.prototype.getDecimals) {
Number.prototype.getDecimals = function() {
var num = this,
match = ('' + num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
if (!match)
return 0;
return Math.max(0, (match[1] ? match[1].length : 0) - (match[2] ? +match[2] : 0));
}
}
It can be used like so:
// Get a number's decimals.
var number = 1.235256;
console.debug(number + " has " + number.getDecimals() + " decimal places.");
// Get a number string's decimals.
var number = "634.2384023";
console.debug(number + " has " + parseFloat(number).getDecimals() + " decimal places.");
Utilizing our existing code, the second case could also be easily added to the String prototype like so:
if (!String.prototype.getDecimals) {
String.prototype.getDecimals = function() {
return parseFloat(this).getDecimals();
}
}
Use this like:
console.debug("45.2342".getDecimals());
A bit of a hybrid of two others on here but this worked for me. Outside cases in my code weren't handled by others here. However, I had removed the scientific decimal place counter. Which I would have loved at uni!
numberOfDecimalPlaces: function (number) {
var match = ('' + number).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
if (!match || match[0] == 0) {
return 0;
}
return match[0].length;
}
Based on Liam Middleton's answer, here's what I did (without scientific notation):
numberOfDecimalPlaces = (number) => {
let match = (number + "").match(/(?:\.(\d+))?$/);
if (!match || !match[1]) {
return 0;
}
return match[1].length;
};
alert(numberOfDecimalPlaces(42.21));
function decimalPlaces(n) {
if (n === NaN || n === Infinity)
return 0;
n = ('' + n).split('.');
if (n.length == 1) {
if (Boolean(n[0].match(/e/g)))
return ~~(n[0].split('e-'))[1];
return 0;
}
n = n[1].split('e-');
return n[0].length + ~~n[1];
}

How to keep leading zero in a timetable

I've got a selection of times, but I want to keep the leading zero:
var fastTrainReading = [0943, 0957, 1006, 1013 , 1027, 1036, 1043, 1057, 1106, 1113, 1127, 1136, 1213, 1227, 1236, 1243, 1257, 1306, 1313, 1327, 1336, 1343, 1357, 1406, 1413, 1427, 1436, 1443, 1457, 1506, 1513, 1527, 1537, 1543, 1559, 1606, 1613, 1627, 1636, 1643, 1657, 1704, 1718, 1728, 1735, 1749, 1758, 1816, 1830, 1847, 1859, 1906, 1911, 1930, 1936, 1941, 1959, 2006, 2017, 2027];
This is the math performed:
var currentTime = hour*100 + mins;
if ((day == 0) || (day == 6)) {
document.write ("There are no buses today");
} else {
var displayCount = 0;
var TrainStr1 = "";
for (var i=0, len=fastTrainReading.length; i<len; ++i) {
if ((fastTrainReading[i] > currentTime) && (displayCount < 2)) {
displayCount = displayCount+1;
TrainStr1=TrainStr1 + fastTrainReading[i] + "<br/>";
}
}
}
document.write (TrainStr1)
I had a pretty good search through, if I missed something feel free to abuse me (but point me in the right direction).
Simplest solution is to store your time data as strings e.g. var fastTrainReading = ['0943', .... JavaScript will cast to integer for you in your calculation routines.
For a comprehensive string formatting solution that adheres to conventional principles, try sprintf() for javascript: http://www.diveintojavascript.com/projects/javascript-sprintf
You can try to use .toString() like: TrainStr1=TrainStr1 +fastTrainReading[i].toString()+ "<br/>"; alt to save your times as strings.
By default you won't get the leading zeroes.
As you know the length of TrainStr1 is 4, you can use the following function to get zeroes.
function formatted(time) {
var s = "0000" + time;
return s.substr(s.length-4); }
You can call the function 'formatted' before using document.write
You need to zero pad your numbers.
Number.prototype.zf = function _zeroFormat(digits)
{
var n = this.toString(), pLen = digits - n.length;
for ( var i = 0; i < pLen; i++)
{
n = '0' + n;
}
return n;
}
if ((fastTrainReading[i] > currentTime.zf(4)) && (displayCount < 2)) {
displayCount = displayCount+1;
TrainStr1=TrainStr1 + fastTrainReading[i] + "<br/>";
}
Once you've normalized all of your numbers to be 0-padded to 4 digits, string comparison is possible. Otherwise, you'll have issues. As things stand, it looks like your code was trying to compare a string (like an element from fastTrainReading) and a number (currentTime).
Just declare your array as strings:
var fastTrainReading = ['0943', '0957', '1006', '1013'];
And don't worry fastTrainReading[i] > currentTime will still work.
'100' > 99 == true

Categories

Resources