JavaScript % (modulo) gives a negative result for negative numbers - javascript

According to Google Calculator (-13) % 64 is 51.
According to Javascript (see this JSBin) it is -13.
How do I fix this?

Number.prototype.mod = function (n) {
"use strict";
return ((this % n) + n) % n;
};
Taken from this article: The JavaScript Modulo Bug

Using Number.prototype is SLOW, because each time you use the prototype method your number is wrapped in an Object. Instead of this:
Number.prototype.mod = function(n) {
return ((this % n) + n) % n;
}
Use:
function mod(n, m) {
return ((n % m) + m) % m;
}
See: https://jsperf.app/negative-modulo/2
~97% faster than using prototype. If performance is of importance to you of course..

The % operator in JavaScript is the remainder operator, not the modulo operator (the main difference being in how negative numbers are treated):
-1 % 8 // -1, not 7

A "mod" function to return a positive result.
var mod = function (n, m) {
var remain = n % m;
return Math.floor(remain >= 0 ? remain : remain + m);
};
mod(5,22) // 5
mod(25,22) // 3
mod(-1,22) // 21
mod(-2,22) // 20
mod(0,22) // 0
mod(-1,22) // 21
mod(-21,22) // 1
And of course
mod(-13,64) // 51

The accepted answer makes me a little nervous because it re-uses the % operator. What if Javascript changes the behavior in the future?
Here is a workaround that does not re-use %:
function mod(a, n) {
return a - (n * Math.floor(a/n));
}
mod(1,64); // 1
mod(63,64); // 63
mod(64,64); // 0
mod(65,64); // 1
mod(0,64); // 0
mod(-1,64); // 63
mod(-13,64); // 51
mod(-63,64); // 1
mod(-64,64); // 0
mod(-65,64); // 63

If x is an integer and n is a power of 2, you can use x & (n - 1) instead of x % n.
> -13 & (64 - 1)
51

Fix negative modulo (reminder operator %)
Simplified using ES6 Arrow function, and without dangerously extending the Number prototype
const mod = (n, m) => (n % m + m) % m;
console.log(mod(-90, 360)); // 270 (Instead of -90)

Though it isn't behaving as you expected, it doesn't mean that JavaScript is not 'behaving'. It is a choice JavaScript made for its modulo calculation. Because, by definition either answer makes sense.
See this from Wikipedia. You can see on the right how different languages chose the result's sign.

This is not a bug, there's 3 functions to calculate modulo, you can use the one which fit your needs (I would recommend to use Euclidean function)
Truncating the decimal part function
console.log( 41 % 7 ); // 6
console.log( -41 % 7 ); // -6
console.log( -41 % -7 ); // -6
console.log( 41 % -7 ); // 6
Integer part function
Number.prototype.mod = function(n) {
return ((this%n)+n)%n;
};
console.log( parseInt( 41).mod( 7) ); // 6
console.log( parseInt(-41).mod( 7) ); // 1
console.log( parseInt(-41).mod(-7) ); // -6
console.log( parseInt( 41).mod(-7) ); // -1
Euclidean function
Number.prototype.mod = function(n) {
var m = ((this%n)+n)%n;
return m < 0 ? m + Math.abs(n) : m;
};
console.log( parseInt( 41).mod( 7) ); // 6
console.log( parseInt(-41).mod( 7) ); // 1
console.log( parseInt(-41).mod(-7) ); // 1
console.log( parseInt( 41).mod(-7) ); // 6

So it seems that if you're trying to mod around degrees (so that if you have -50 degrees - 200 degrees), you'd want to use something like:
function modrad(m) {
return ((((180+m) % 360) + 360) % 360)-180;
}

I deal with négative a and negative n too
//best perf, hard to read
function modul3(a,n){
r = a/n | 0 ;
if(a < 0){
r += n < 0 ? 1 : -1
}
return a - n * r
}
// shorter code
function modul(a,n){
return a%n + (a < 0 && Math.abs(n));
}
//beetween perf and small code
function modul(a,n){
return a - n * Math[n > 0 ? 'floor' : 'ceil'](a/n);
}

There is a NPM package that will do the work for you. You can install it with the following command.
npm install just-modulo --save
Usage copied from the README
import modulo from 'just-modulo';
modulo(7, 5); // 2
modulo(17, 23); // 17
modulo(16.2, 3.8); // 17
modulo(5.8, 3.4); //2.4
modulo(4, 0); // 4
modulo(-7, 5); // 3
modulo(-2, 15); // 13
modulo(-5.8, 3.4); // 1
modulo(12, -1); // NaN
modulo(-3, -8); // NaN
modulo(12, 'apple'); // NaN
modulo('bee', 9); // NaN
modulo(null, undefined); // NaN
GitHub repository can be found via the following link:
https://github.com/angus-c/just/tree/master/packages/number-modulo

For fun, here's a "wrap" function that works sorta like a modulo, except you can also specify the minimum value of the range (instead of it being 0):
const wrap = (value = 0, min = 0, max = 10) =>
((((value - min) % (max - min)) + (max - min)) % (max - min)) + min;
Basically just takes the true modulo formula, offsets it such that min ends up at 0, then adds min back in after.
Useful if you have a value that you want to keep between two values.

Related

Rounding of negative numbers in Javascript

We have come across a problem with Math.round() in JavaScript. The problem is that this function doesn't round correctly for negative numbers. For example :
1.5 ~= 2
0.5 ~= 1
-0.5 ~= 0 // Wrong
-1.5 ~= -1 // Wrong
And this is not correct according to arithmetic rounding. The correct numbers for -0.5 should be -1 and -1.5 should be -2.
Is there any standard way, to correctly round negative numbers in Javascript ?
Apply Math.round after converting to a positive number and finally roll back the sign. Where you can use Math.sign method to get the sign from the number and Math.abs to get the absolute of the number.
console.log(
Math.sign(num) * Math.round(Math.sign(num) * num),
// or
Math.sign(num) * Math.round(Math.abs(num))
)
var nums = [-0.5, 1.5, 3, 3.6, -4.8, -1.3];
nums.forEach(function(num) {
console.log(
Math.sign(num) * Math.round(Math.sign(num) * num),
Math.sign(num) * Math.round(Math.abs(num))
)
});
You could save the sign and apply later, in ES5;
function round(v) {
return (v >= 0 || -1) * Math.round(Math.abs(v));
}
console.log(round(1.5)); // 2
console.log(round(0.5)); // 1
console.log(round(-1.5)); // -2
console.log(round(-0.5)); // -1
You could try using Math.ceil(num) to round num and then - 1 if num was negative, e.g.
if (num < 0) {
num = Math.ceil(num) - 1;
} else {
num = Math.ceil(num);
}
ES6 has added a method called Math.trunc using which we can get the integer part of a decimal number
The Math.trunc() function returns the integer part of a number by
removing any fractional digits.
Math.trunc(42.84) -> Returns 42
Math.trunc(5.3) -> Returns 5
Math.trunc(-4.3) -> Returns -4
Math.trunc(-3.123) -> Returns -3
var r = (Math.random() * 200) - 100;
How about purely evaluating the result without using the math library? eg, by using a ternary operator, you can elegantly check for negative numbers and then floor after "rounding":
var n = r + (r < 0 ? -0.5 : 0.5) | 0;
The | 0 is just a silly trick in js that "overloads" the binary operator (you could use any binary operator) in order to truncate the number.
Note that this is not flooring (like Math.floor), since Math.floor(-3.2), for example, will actually yield -4.
One could even do something similar to #Balan's answer (I like that one and the one below, but I feel like this or the ternary operator will just be a touch faster--I am probably wrong, though, because the Math libraries have been proven to be very fast):
var n = (r + Math.sign(r) / 2) | 0;
probably the fastest, most elegant way:
var n = Math.floor(r + 0.5);
example:
var body = document.getElementById("myTable").children[1];
var i, iMax = 100, r, tr, td;
for (i = 0; i < iMax; i++) {
r = Math.random() * 200 - 100;
tr = document.createElement("tr");
td = document.createElement("td");
td.innerHTML = r;
tr.appendChild(td);
td = document.createElement("td");
td.innerHTML = (r + Math.sign(r) / 2) | 0;
tr.appendChild(td);
body.appendChild(tr);
}
#myTable {
min-width: 250px;
}
<table id="myTable">
<thead>
<tr>
<th>float</th>
<th>round</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
Rounding with precision.
Rounds to Int by default or, if second argument is provided, to n digits after decimal point.
+ '1' fixes incorrect rounding for .0X5 numbers.
function round(num, digits=0) {
if (!(num % 1)) return num
return +Number(num + '1').toFixed(digits)
}
First observe that Math.round(v) is defined as Math.floor(v + 0.5):
Math.round(-1.7) === -2
Math.round(-1.3) === -1
Math.floor(-1.7 + 0.5) === -2
Math.floor(-1.3 + 0.5) === -1
Then realize that parseInt(v) is similar to Math.floor(v), however, it handles negative numbers differently (exactly how you expected it to behave):
Math.floor(1.7) === 1
Math.floor(-1.7) === -2
parseInt(1.7) === 1
parseInt(-1.7) === -1
So the parseInt(v) behavior is what you want, but instead of flooring, you want rounding. In order to apply this to any number, we need to add +0.5 for positive numbers, and -0.5 for negative numbers. So the solution is this function:
var parseIntRound = function(v)
{
return parseInt(v + Math.sign(v)/2);
};
// or with modern syntactic sugar:
// const parseIntRound = v => parseInt(v + Math.sign(v)/2);
parseIntRound( 1.5) === 2
parseIntRound( 0.5) === 1
parseIntRound(-0.5) === -1
parseIntRound(-1.3) === -1
parseIntRound(-1.5) === -2
parseIntRound(-1.7) === -2
Where Math.sign(v) returns 1 for any positive number (>0), -1 for any negative number (<0), and 0 for positive zero (and -0 for negative zero).

Using Javascript to convert radians to degrees with positive and negative values [duplicate]

According to Google Calculator (-13) % 64 is 51.
According to Javascript (see this JSBin) it is -13.
How do I fix this?
Number.prototype.mod = function (n) {
"use strict";
return ((this % n) + n) % n;
};
Taken from this article: The JavaScript Modulo Bug
Using Number.prototype is SLOW, because each time you use the prototype method your number is wrapped in an Object. Instead of this:
Number.prototype.mod = function(n) {
return ((this % n) + n) % n;
}
Use:
function mod(n, m) {
return ((n % m) + m) % m;
}
See: https://jsperf.app/negative-modulo/2
~97% faster than using prototype. If performance is of importance to you of course..
The % operator in JavaScript is the remainder operator, not the modulo operator (the main difference being in how negative numbers are treated):
-1 % 8 // -1, not 7
A "mod" function to return a positive result.
var mod = function (n, m) {
var remain = n % m;
return Math.floor(remain >= 0 ? remain : remain + m);
};
mod(5,22) // 5
mod(25,22) // 3
mod(-1,22) // 21
mod(-2,22) // 20
mod(0,22) // 0
mod(-1,22) // 21
mod(-21,22) // 1
And of course
mod(-13,64) // 51
The accepted answer makes me a little nervous because it re-uses the % operator. What if Javascript changes the behavior in the future?
Here is a workaround that does not re-use %:
function mod(a, n) {
return a - (n * Math.floor(a/n));
}
mod(1,64); // 1
mod(63,64); // 63
mod(64,64); // 0
mod(65,64); // 1
mod(0,64); // 0
mod(-1,64); // 63
mod(-13,64); // 51
mod(-63,64); // 1
mod(-64,64); // 0
mod(-65,64); // 63
If x is an integer and n is a power of 2, you can use x & (n - 1) instead of x % n.
> -13 & (64 - 1)
51
Fix negative modulo (reminder operator %)
Simplified using ES6 Arrow function, and without dangerously extending the Number prototype
const mod = (n, m) => (n % m + m) % m;
console.log(mod(-90, 360)); // 270 (Instead of -90)
Though it isn't behaving as you expected, it doesn't mean that JavaScript is not 'behaving'. It is a choice JavaScript made for its modulo calculation. Because, by definition either answer makes sense.
See this from Wikipedia. You can see on the right how different languages chose the result's sign.
This is not a bug, there's 3 functions to calculate modulo, you can use the one which fit your needs (I would recommend to use Euclidean function)
Truncating the decimal part function
console.log( 41 % 7 ); // 6
console.log( -41 % 7 ); // -6
console.log( -41 % -7 ); // -6
console.log( 41 % -7 ); // 6
Integer part function
Number.prototype.mod = function(n) {
return ((this%n)+n)%n;
};
console.log( parseInt( 41).mod( 7) ); // 6
console.log( parseInt(-41).mod( 7) ); // 1
console.log( parseInt(-41).mod(-7) ); // -6
console.log( parseInt( 41).mod(-7) ); // -1
Euclidean function
Number.prototype.mod = function(n) {
var m = ((this%n)+n)%n;
return m < 0 ? m + Math.abs(n) : m;
};
console.log( parseInt( 41).mod( 7) ); // 6
console.log( parseInt(-41).mod( 7) ); // 1
console.log( parseInt(-41).mod(-7) ); // 1
console.log( parseInt( 41).mod(-7) ); // 6
So it seems that if you're trying to mod around degrees (so that if you have -50 degrees - 200 degrees), you'd want to use something like:
function modrad(m) {
return ((((180+m) % 360) + 360) % 360)-180;
}
I deal with négative a and negative n too
//best perf, hard to read
function modul3(a,n){
r = a/n | 0 ;
if(a < 0){
r += n < 0 ? 1 : -1
}
return a - n * r
}
// shorter code
function modul(a,n){
return a%n + (a < 0 && Math.abs(n));
}
//beetween perf and small code
function modul(a,n){
return a - n * Math[n > 0 ? 'floor' : 'ceil'](a/n);
}
There is a NPM package that will do the work for you. You can install it with the following command.
npm install just-modulo --save
Usage copied from the README
import modulo from 'just-modulo';
modulo(7, 5); // 2
modulo(17, 23); // 17
modulo(16.2, 3.8); // 17
modulo(5.8, 3.4); //2.4
modulo(4, 0); // 4
modulo(-7, 5); // 3
modulo(-2, 15); // 13
modulo(-5.8, 3.4); // 1
modulo(12, -1); // NaN
modulo(-3, -8); // NaN
modulo(12, 'apple'); // NaN
modulo('bee', 9); // NaN
modulo(null, undefined); // NaN
GitHub repository can be found via the following link:
https://github.com/angus-c/just/tree/master/packages/number-modulo
For fun, here's a "wrap" function that works sorta like a modulo, except you can also specify the minimum value of the range (instead of it being 0):
const wrap = (value = 0, min = 0, max = 10) =>
((((value - min) % (max - min)) + (max - min)) % (max - min)) + min;
Basically just takes the true modulo formula, offsets it such that min ends up at 0, then adds min back in after.
Useful if you have a value that you want to keep between two values.

Javascript: Round up to the next multiple of 5

I need a utility function that takes in an integer value (ranging from 2 to 5 digits in length) that rounds up to the next multiple of 5 instead of the nearest multiple of 5. Here is what I got:
function round5(x)
{
return (x % 5) >= 2.5 ? parseInt(x / 5) * 5 + 5 : parseInt(x / 5) * 5;
}
When I run round5(32), it gives me 30, where I want 35.
When I run round5(37), it gives me 35, where I want 40.
When I run round5(132), it gives me 130, where I want 135.
When I run round5(137), it gives me 135, where I want 140.
etc...
How do I do this?
This will do the work:
function round5(x)
{
return Math.ceil(x/5)*5;
}
It's just a variation of the common rounding number to nearest multiple of x function Math.round(number/x)*x, but using .ceil instead of .round makes it always round up instead of down/up according to mathematical rules.
const roundToNearest5 = x => Math.round(x/5)*5
This will round the number to the nearest 5. To always round up to the nearest 5, use Math.ceil. Likewise, to always round down, use Math.floor instead of Math.round.
You can then call this function like you would any other. For example,
roundToNearest5(21)
will return:
20
Like this?
function roundup5(x) { return (x%5)?x-x%5+5:x }
I arrived here while searching for something similar.
If my number is —0, —1, —2 it should floor to —0, and if it's —3, —4, —5 it should ceil to —5.
I came up with this solution:
function round(x) { return x%5<3 ? (x%5===0 ? x : Math.floor(x/5)*5) : Math.ceil(x/5)*5 }
And the tests:
for (var x=40; x<51; x++) {
console.log(x+"=>", x%5<3 ? (x%5===0 ? x : Math.floor(x/5)*5) : Math.ceil(x/5)*5)
}
// 40 => 40
// 41 => 40
// 42 => 40
// 43 => 45
// 44 => 45
// 45 => 45
// 46 => 45
// 47 => 45
// 48 => 50
// 49 => 50
// 50 => 50
voici 2 solutions possibles :
y= (x % 10==0) ? x : x-x%5 +5; //......... 15 => 20 ; 37 => 40 ; 41 => 45 ; 20 => 20 ;
z= (x % 5==0) ? x : x-x%5 +5; //......... 15 => 15 ; 37 => 40 ; 41 => 45 ; 20 => 20 ;
Regards
Paul
New answer for old question, without if nor Math
x % 5: the remainder
5 - x % 5: the amount need to add up
(5 - x % 5) % 5: make sure it less than 5
x + (5 - x % 5) % 5: the result (x or next multiple of 5)
~~((x + N - 1) / N): equivalent to Math.ceil(x / N)
function round5(x) {
return x + (5 - x % 5) % 5;
}
function nearest_multiple_of(N, x) {
return x + (N - x % N) % N;
}
function other_way_nearest_multiple_of(N, x) {
return ~~((x + N - 1) / N) * N;
}
console.info(nearest_multiple_of(5, 0)); // 0
console.info(nearest_multiple_of(5, 2022)); // 2025
console.info(nearest_multiple_of(5, 2025)); // 2025
console.info(other_way_nearest_multiple_of(5, 2022)); // 2025
console.info(other_way_nearest_multiple_of(5, 2025)); // 2025
// round with precision
var round = function (value, precision) {
return Math.round(value * Math.pow(10, precision)) / Math.pow(10, precision);
};
// round to 5 with precision
var round5 = (value, precision) => {
return round(value * 2, precision) / 2;
}
const fn = _num =>{
return Math.round(_num)+ (5 -(Math.round(_num)%5))
}
reason for using round is that expected input can be a random number.
Thanks!!!
I solved it using a while loop, or any other loop for that matter. What is important is to increase the number say n, until n % 5 == 0; Something like this
while(n % 5 != 0) {
n++;
}
return n;
if( x % 5 == 0 ) {
return int( Math.floor( x / 5 ) ) * 5;
} else {
return ( int( Math.floor( x / 5 ) ) * 5 ) + 5;
}
maybe?

How does JavaScript handle modulo?

I was wondering how JavaScript handles modulo. For example, what would JavaScript evaluate 47 % 8 as? I can’t seem to find any documentation on it, and my skills on modulo aren’t the best.
Exactly as every language handles modulo: The remainder of X / Y.
47 % 8 == 7
Also if you use a browser like Firefox + Firebug, Safari, Chrome, or even IE8+ you could test such an operation as quickly as hitting F12.
Javascript's modulo operator returns a negative number when given a negative number as input (on the left side).
14 % 5 // 4
15 % 5 // 0
-15 % 5 // -0
-14 % 5 // -4
(Note: negative zero is a distinct value in JavaScript and other languages with IEEE floats, but -0 === 0 so you usually don't have to worry about it.)
If you want a number that is always between 0 and a positive number that you specify, you can define a function like so:
function mod(n, m) {
return ((n % m) + m) % m;
}
mod(14, 5) // 4
mod(15, 5) // 4
mod(-15, 5) // 0
mod(-14, 5) // 1
Modulo should behave like you expect. I expect.
47 % 8 == 7
Fiddle Link
TO better understand modulo here is how its built;
function modulo(num1, num2) {
if (typeof num1 != "number" || typeof num2 != "number"){
return NaN
}
var num1isneg=false
if (num1.toString().includes("-")){
num1isneg=true
}
num1=parseFloat(num1.toString().replace("-",""))
var leftover =parseFloat( ( parseFloat(num1/num2) - parseInt(num1/num2)) *num2)
console.log(leftover)
if (num1isneg){
var z = leftover.toString().split("")
z= ["-", ...z]
leftover = parseFloat(z.join(""))
}
return leftover
}

Implementation of Luhn algorithm

I am trying to implement simple validation of credit card numbers. I read about the Luhn algorithm on Wikipedia:
Counting from the check digit, which is the rightmost, and moving
left, double the value of every second digit.
Sum the digits of the products (e.g., 10: 1 + 0 = 1, 14: 1 + 4 = 5)
together with the undoubled digits from the original number.
If the total modulo 10 is equal to 0 (if the total ends in zero)
then the number is valid according to the Luhn formula; else it is
not valid.
On Wikipedia, the description of the Luhn algorithm is very easily understood. However, I have also seen other implementations of the Luhn algorithm on Rosetta Code and elsewhere (archived).
Those implementations work very well, but I am confused about why they can use an array to do the work. The array they use seems to have no relation with Luhn algorithm, and I can't see how they achieve the steps described on Wikipedia.
Why are they using arrays? What is the significance of them, and how are they used to implement the algorithm as described by Wikipedia?
Unfortunately none of the codes above worked for me. But I found on GitHub a working solution
// takes the form field value and returns true on valid number
function valid_credit_card(value) {
// accept only digits, dashes or spaces
if (/[^0-9-\s]+/.test(value)) return false;
// The Luhn Algorithm. It's so pretty.
var nCheck = 0, nDigit = 0, bEven = false;
value = value.replace(/\D/g, "");
for (var n = value.length - 1; n >= 0; n--) {
var cDigit = value.charAt(n),
nDigit = parseInt(cDigit, 10);
if (bEven) {
if ((nDigit *= 2) > 9) nDigit -= 9;
}
nCheck += nDigit;
bEven = !bEven;
}
return (nCheck % 10) == 0;
}
the array [0,1,2,3,4,-4,-3,-2,-1,0] is used as a look up array for finding the difference between a number in 0-9 and the digit sum of 2 times its value. For example, for number 8, the difference between 8 and (2*8) = 16 -> 1+6 = 7 is 7-8 = -1.
Here is graphical presentation, where {n} stand for sum of digit of n
[{0*2}-0, {1*2}-1, {2*2}-2, {3*2}-3, {4*2}-4, {5*2}-5, {6*2}-6, {7*2}-7....]
| | | | | | | |
[ 0 , 1 , 2 , 3 , 4 , -4 , -3 , -2 ....]
The algorithm you listed just sum over all the digit and for each even spot digit, look up the the difference using the array, and apply it to the total sum.
Compact Luhn validator:
var luhn_validate = function(imei){
return !/^\d+$/.test(imei) || (imei.split('').reduce(function(sum, d, n){
return sum + parseInt(((n + imei.length) %2)? d: [0,2,4,6,8,1,3,5,7,9][d]);
}, 0)) % 10 == 0;
};
Works fine for both CC and IMEI numbers. Fiddle: http://jsfiddle.net/8VqpN/
Lookup tables or arrays can simplify algorithm implementations - save many lines of code - and with that increase performance... if the calculation of the lookup index is simple - or simpler - and the array's memory footprint is affordable.
On the other hand, understanding how the particular lookup array or data structure came to be can at times be quite difficult, because the related algorithm implementation may look - at first sight - quite different from the original algorithm specification or description.
Indication to use lookup tables are number oriented algorithms with simple arithmetics, simple comparisons, and equally structured repetition patterns - and of course - of quite finite value sets.
The many answers in this thread go for different lookup tables and with that for different algorithms to implement the very same Luhn algorithm. Most implementations use the lookup array to avoid the cumbersome figuring out of the value for doubled digits:
var luhnArr = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9];
//
// ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
// | | | | | | | | | |
//
// - d-igit=index: 0 1 2 3 4 5 6 7 8 9
// - 1st
// calculation: 2*0 2*2 2*2 2*3 2*4 2*5 2*6 2*7 2*8 2*9
// - intermeduate
// value: = 0 = 2 = 4 = 6 = 8 =10 =12 =14 =16 =18
// - 2nd
// calculation: 1+0 1+2 1+4 1+6 1+8
//
// - final value: 0 2 4 6 8 =1 =3 =5 =7 =9
//
var luhnFinalValue = luhnArray[d]; // d is numeric value of digit to double
An equal implementation for getting the luhnFinalValue looks like this:
var luhnIntermediateValue = d * 2; // d is numeric value of digit to double
var luhnFinalValue = (luhnIntermediateValue < 10)
? luhnIntermediateValue // (d ) * 2;
: luhnIntermediateValue - 10 + 1; // (d - 5) * 2 + 1;
Which - with the comments in above true and false terms - is of course simplified:
var luhnFinalValue = (d < 5) ? d : (d - 5) * 2 + 1;
Now I'm not sure if I 'saved' anything at all... ;-) especially thanks the value-formed or short form of if-then-else. Without it, the code may look like this - with 'orderly' blocks
and embedded in the next higher context layer of the algorithm and therefore luhnValue:
var luhnValue; // card number is valid when luhn values for each digit modulo 10 is 0
if (even) { // even as n-th digit from the the end of the string of digits
luhnValue = d;
} else { // doubled digits
if (d < 5) {
luhnValue = d * 2;
} else {
lunnValue = (d - 5) * 2 + 1;
}
}
Or:
var luhnValue = (even) ? d : (d < 5) ? d * 2 : (d - 5) * 2 + 1;
Btw, with modern, optimizing interpreters and (just in time) compilers, the difference is only in the source code and matters only for readability.
Having come that far with explanation - and 'justification' - of the use of lookup tables and comparison to straight forward coding, the lookup table looks now a bit overkill to me. The algorithm without is now quite easy to finish - and it looks pretty compact too:
function luhnValid(cardNo) { // cardNo as a string w/ digits only
var sum = 0, even = false;
cardNo.split("").reverse().forEach(function(dstr){ d = parseInt(dstr);
sum += ((even = !even) ? d : (d < 5) ? d * 2 : (d - 5) * 2 + 1);
});
return (sum % 10 == 0);
}
What strikes me after going through the explanation exercise is that the initially most enticing implementation - the one using reduce() from #kalypto - just lost totally its luster for me... not only because it is faulty on several levels, but more so because it shows that bells and whistles may not always 'ring the victory bell'. But thank you, #kalypto, it made me actually use - and understand - reduce():
function luhnValid2(cardNo) { // cardNo as a string w/ digits only
var d = 0, e = false; // e = even = n-th digit counted from the end
return ( cardNo.split("").reverse().reduce(
function(s,dstr){ d = parseInt(dstr); // reduce arg-0 - callback fnc
return (s + ((e = !e) ? d : [0,2,4,6,8,1,3,5,7,9][d]));
} // /end of callback fnc
,0 // reduce arg-1 - prev value for first iteration (sum)
) % 10 == 0
);
}
To be true to this thread, some more lookup table options have to be mentioned:
how about just adjust varues for doubled digits - as posted by #yngum
how about just everything with lookup tables - as posted by #Simon_Weaver - where also the values for the non-doubled digits are taken from a look up table.
how about just everything with just ONE lookup table - as inspired by the use of an offset as done in the extensively discussed luhnValid() function.
The code for the latter - using reduce - may look like this:
function luhnValid3(cardNo) { // cardNo as a string w/ digits only
var d = 0, e = false; // e = even = n-th digit counted from the end
return ( cardNo.split("").reverse().reduce(
function(s,dstr){ d = parseInt(dstr);
return (s + [0,1,2,3,4,5,6,7,8,9,0,2,4,6,8,1,3,5,7,9][d+((e=!e)?0:10)]);
}
,0
) % 10 == 0
);
}
And for closing lunValid4() - very compact - and using just 'old fashioned' (compatible) JavaScript - with one single lookup table:
function luhnValid4(cardNo) { // cardNo as a string w/ digits only
var s = 0, e = false, p = cardNo.length; while (p > 0) { p--;
s += "01234567890246813579".charAt(cardNo.charAt(p)*1 + ((e=!e)?0:10)) * 1; }
return (s % 10 == 0);
}
Corollar: Strings can be looked at as lookup tables of characters... ;-)
A perfect example of a nice lookup table application is the counting of set bits in bits lists - bits set in a a (very) long 8-bit byte string in (an interpreted) high-level language (where any bit operations are quite expensive). The lookup table has 256 entries. Each entry contains the number of bits set in an unsigned 8-bit integer equal to the index of the entry. Iterating through the string and taking the unsigned 8-bit byte equal value to access the number of bits for that byte from the lookup table. Even for low-level language - such as assembler / machine code - the lookup table is the way to go... especially in an environment, where the microcode (instruction) can handle multiple bytes up to 256 or more in an (single CISC) instruction.
Some notes:
numberString * 1 and parseInt(numberStr) do about the same.
there are some superfluous indentations, parenthesis,etc... supporting my brain in getting the semantics quicker... but some that I wanted to leave out, are actually required... when
it comes to arithmetic operations with short-form, value-if-then-else expressions as terms.
some formatting may look new to you; for examples, I use the continuation comma with the
continuation on the same line as the continuation, and I 'close' things - half a tab - indented to the 'opening' item.
All formatting is all done for the human, not the computer... 'it' does care less.
algorithm datastructure luhn lookuptable creditcard validation bitlist
A very fast and elegant implementation of the Luhn algorithm following:
const isLuhnValid = function luhn(array) {
return function (number) {
let len = number ? number.length : 0,
bit = 1,
sum = 0;
while (len--) {
sum += !(bit ^= 1) ? parseInt(number[len], 10) : array[number[len]];
}
return sum % 10 === 0 && sum > 0;
};
}([0, 2, 4, 6, 8, 1, 3, 5, 7, 9]);
console.log(isLuhnValid("4112344112344113".split(""))); // true
console.log(isLuhnValid("4112344112344114".split(""))); // false
On my dedicated git repository you can grab it and retrieve more info (like benchmarks link and full unit tests for ~50 browsers and some node.js versions).
Or you can simply install it via bower or npm. It works both on browsers and/or node.
bower install luhn-alg
npm install luhn-alg
If you want to calculate the checksum, this code from this page is very concise and in my random tests seems to work.
NOTE: the verification algorithmns on this page do NOT all work.
// Javascript
String.prototype.luhnGet = function()
{
var luhnArr = [[0,1,2,3,4,5,6,7,8,9],[0,2,4,6,8,1,3,5,7,9]], sum = 0;
this.replace(/\D+/g,"").replace(/[\d]/g, function(c, p, o){
sum += luhnArr[ (o.length-p)&1 ][ parseInt(c,10) ]
});
return this + ((10 - sum%10)%10);
};
alert("54511187504546384725".luhnGet());​
Here's my findings for C#
function luhnCheck(value) {
return 0 === (value.replace(/\D/g, '').split('').reverse().map(function(d, i) {
return +['0123456789','0246813579'][i % 2][+d];
}).reduce(function(p, n) {
return p + n;
}) % 10);
}
Update: Here's a smaller version w/o string constants:
function luhnCheck(value) {
return !(value.replace(/\D/g, '').split('').reverse().reduce(function(a, d, i) {
return a + d * (i % 2 ? 2.2 : 1) | 0;
}, 0) % 10);
}
note the use of 2.2 here is to make doubling d roll over with an extra 1 when doubling 5 to 9.
Code is the following:
var LuhnCheck = (function()
{
var luhnArr = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9];
return function(str)
{
var counter = 0;
var incNum;
var odd = false;
var temp = String(str).replace(/[^\d]/g, "");
if ( temp.length == 0)
return false;
for (var i = temp.length-1; i >= 0; --i)
{
incNum = parseInt(temp.charAt(i), 10);
counter += (odd = !odd)? incNum : luhnArr[incNum];
}
return (counter%10 == 0);
}
})();
The variable counter is the sum of all the digit in odd positions, plus the double of the digits in even positions, when the double exceeds 10 we add the two numbers that make it (ex: 6 * 2 -> 12 -> 1 + 2 = 3)
The Array you are asking about is the result of all the possible doubles
var luhnArr = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9];
0 * 2 = 0 --> 0
1 * 2 = 2 --> 2
2 * 2 = 4 --> 4
3 * 2 = 6 --> 6
4 * 2 = 8 --> 8
5 * 2 = 10 --> 1+0 --> 1
6 * 2 = 12 --> 1+2 --> 3
7 * 2 = 14 --> 1+4 --> 5
8 * 2 = 16 --> 1+6 --> 7
9 * 2 = 18 --> 1+8 --> 9
So for example
luhnArr[3] --> 6 (6 is in 3rd position of the array, and also 3 * 2 = 6)
luhnArr[7] --> 5 (5 is in 7th position of the array, and also 7 * 2 = 14 -> 5 )
Another alternative:
function luhn(digits) {
return /^\d+$/.test(digits) && !(digits.split("").reverse().map(function(checkDigit, i) {
checkDigit = parseInt(checkDigit, 10);
return i % 2 == 0
? checkDigit
: (checkDigit *= 2) > 9 ? checkDigit - 9 : checkDigit;
}).reduce(function(previousValue, currentValue) {
return previousValue + currentValue;
}) % 10);
}
Alternative ;) Simple and Best
<script>
// takes the form field value and returns true on valid number
function valid_credit_card(value) {
// accept only digits, dashes or spaces
if (/[^0-9-\s]+/.test(value)) return false;
// The Luhn Algorithm. It's so pretty.
var nCheck = 0, nDigit = 0, bEven = false;
value = value.replace(/\D/g, "");
for (var n = value.length - 1; n >= 0; n--) {
var cDigit = value.charAt(n),
nDigit = parseInt(cDigit, 10);
if (bEven) {
if ((nDigit *= 2) > 9) nDigit -= 9;
}
nCheck += nDigit;
bEven = !bEven;
}
return (nCheck % 10) == 0;
}
console.log(valid_credit_card("5610591081018250"),"valid_credit_card Validation");
</script>
Best Solution here
http://plnkr.co/edit/34aR8NUpaKRCYpgnfUbK?p=preview
with all test cases passed according to
http://www.paypalobjects.com/en_US/vhelp/paypalmanager_help/credit_card_numbers.htm
and the credit goes to
https://gist.github.com/DiegoSalazar/4075533
const LuhnCheckCard = (number) => {
if (/[^0-9-\s]+/.test(number) || number.length === 0)
return false;
return ((number.split("").map(Number).reduce((prev, digit, i) => {
(!(( i & 1 ) ^ number.length)) && (digit *= 2);
(digit > 9) && (digit -= 9);
return prev + digit;
}, 0) % 10) === 0);
}
console.log(LuhnCheckCard("4532015112830366")); // true
console.log(LuhnCheckCard("gdsgdsgdsg")); // false
I worked out the following solution after I submitted a much worse one for a test..
function valid(number){
var splitNumber = parseInt(number.toString().split(""));
var totalEvenValue = 0;
var totalOddValue = 0;
for(var i = 0; i < splitNumber.length; i++){
if(i % 2 === 0){
if(splitNumber[i] * 2 >= 10){
totalEvenValue += splitNumber[i] * 2 - 9;
} else {
totalEvenValue += splitNumber[i] * 2;
}
}else {
totalOddValue += splitNumber[i];
}
}
return ((totalEvenValue + totalOddValue) %10 === 0)
}
console.log(valid(41111111111111111));
I recently wrote a solution using Javascript, I leave the code here for anyone who can help:
// checksum with Luhn Algorithm
const luhn_checksum = function(strIn) {
const len = strIn.length;
let sum = 0
for (let i = 0; i<10; i += 1) {
let factor = (i % 2 === 1) ? 2: 1
const v = parseInt(strIn.charAt(i), 10) * factor
sum += (v>9) ? (1 + v % 10) : v
}
return (sum * 9) % 10
}
// teste exampple on wikipedia:
// https://en.wikipedia.org/wiki/Luhn_algorithm
const strIn = "7992739871"
// The checksum of "7992739871" is 3
console.log(luhn_checksum(strIn))
If you understand this code above, you will have no problem converting it to any other language.
For example in python:
def nss_checksum(nss):
suma = 0
for i in range(10):
factor = 2 if (i % 2 == 1) else 1
v = int(nss[i]) * factor
suma += (1 + v % 10) if (v >9) else v
return (suma * 9) % 10
For more info, check this:
https://en.wikipedia.org/wiki/Luhn_algorithm
My Code(En español):
https://gist.github.com/fitorec/82a3e27fae3bab709a07c19c71c3a8d4
def validate_credit_card_number(card_number):
if(len(str(card_number))==16):
group1 = []
group1_double = []
after_group_double = []
group1_sum = 0
group2_sum = 0
group2 = []
total_final_sum = 0
s = str(card_number)
list1 = [int(i) for i in list(s)]
for i in range(14, -1, -2):
group1.append(list1[i])
for x in group1:
b = 0
b = x * 2
group1_double.append(b)
for j in group1_double:
if(j > 9):
sum_of_digits = 0
alias = str(j)
temp1 = alias[0]
temp2 = alias[1]
sum_of_digits = int(temp1) + int(temp2)
after_group_double.append(sum_of_digits)
else:
after_group_double.append(j)
for i in after_group_double:
group1_sum += i
for i in range(15, -1, -2):
group2.append(list1[i])
for i in group2:
group2_sum += i
total_final_sum = group1_sum + group2_sum
if(total_final_sum%10==0):
return True
else:
return False
card_number= 1456734512345698 #4539869650133101 #1456734512345698 # #5239512608615007
result=validate_credit_card_number(card_number)
if(result):
print("credit card number is valid")
else:
print("credit card number is invalid")

Categories

Resources