Im working on JavaScript to get three different algorithms to work in the same code, I set up a function for each algorithm. I'm trying to get three Primality testing methods: Trial Division, the Fermat Primality Test, and the Miller-Rabin Primality Test. The first two are working fine but the Miller-Rabin isn't. I'm pretty new to JavaScript and programming in general, so if you can find where I went wrong or can think of a way to make it work, please let me know! Thanks!
// 1531 6389 68819 688889 6388819
// 68883889 688838831 1000000009
// 561 is a Carmichael number; a Fermat pseudoprime with the property a^n-1 = 1 mod n, for any "a" coprime to 561.
input = 5491763;
numTrials = 2000;
document.getElementById("input").innerHTML = input;
function TrialDiv(n) {
if (n === 1) {
return false;
} else if (n === 2) {
return true;
} else {
for (var x = 2; x < n; x++) {
if (n % x === 0) {
return false;
}
}
return true;
}
}
if ((TrialDiv(input)) === true) {
a = "Prime"
} else if ((TrialDiv(input)) === false) {
a = "Composite"
}
//---------------------------------------------------------------------------
function gcd(x, y) {
while (y !== 0) {
var z = x % y;
x = y;
y = z;
}
return x;
}
function getRndInteger(max) {
return Math.floor(Math.random() * (max - 2)) + 2;
}
//--------------------------------------------------------------------------
function Fermat(n) {
for (var t = 0; t = numTrials; t++) {
m = getRndInteger(input);
if (gcd(m, n) !== 1) {
return false;
}
}
return (Math.pow(m, n - 1) % n !== 1);
}
if ((Fermat(input)) === true) {
b = "Prime";
} else if ((Fermat(input)) === false) {
b = "Composite";
}
//---------------------------------------------------------------------------
function genD(n) { // Generates "d" such that "n-1 = 2^s * d"
var p = n - 1;
var d = p / 2;
while (d % 2 === 0) {
d = d / 2;
}
return d;
}
function genS() { // Generates "s" such that "n-1 = 2^s * d"
var s = Math.log2(p / d);
return s;
}
//---------------------------------------------------------------------------
function MillerRabin(n) {
for (var t = 0; t < numTrials; t++) {
m = getRndInteger(input);
if (gcd(m, n) !== 1) {
return false;
} else {
for (var r = 0; r < genS(); r++) {
power = (Math.pow(2, r) * genD(input));
if (Math.pow(m, genD(input)) % n === 1 || Math.pow(m, power) % n === -1) {
return true;
} else {
return false;
}
}
return true;
}
return true;
}
}
if ((MillerRabin(input)) === true) {
c = "Prime";
} else if ((MillerRabin(input)) === false) {
c = "Composite";
}
<body>
<button type="button" onclick='document.getElementById("TrialDivision").innerHTML = a; document.getElementById("FermatTest").innerHTML = b; document.getElementById("MillerRabinTest").innerHTML = c; '>Show</button>
<hr>
<b style="color:rgb(0,0,120)">PRIMALITY TESTS</b>
<p></p>
Input:
<l id="input"></l>
<hr>
<h5 style="color:rgb(160,0,0)">TRIAL DIVISION</h5>
<p></p>
Output:
<i id="TrialDivision"></i>
<hr>
<h5 style="color:rgb(160,0,0)">FERMAT PRIMALITY TEST</h5>
<p></p>
Output:
<i id="FermatTest"></i>
<hr>
<h5 style="color:rgb(160,0,0)">MILLER-RABIN PRIMALITY TEST</h5>
<p></p>
Output:
<i id="MillerRabinTest"></i>
</body>
<script>
That's how I wrote it up, this was purely created by me from the original mathematical algorithms for each test. What happens is that the Miller-Rabin Output doesn't show anything when the input number is prime; the algorithm isn't able to identify it. But it does identify composites correctly.
Please let me know of any improvements you think of!
You have some problems with loops not running. I'm not sure how the algorithm is supposed to work, so I don't if it's working or not, but the immediate problem is cause by leaky variable and variables not declared in functions (which makes them global).
The fix for this immediate problem is to declare the local variables in the functions so you don't depend on having them set by some other function.
function genD(n) { // Generates "d" such that "n-1 = 2^s * d"
var p = n - 1;
var d = p / 2;
while (d % 2 === 0) {
d = d / 2;
}
return d;
}
function genS(n) { // Generates "s" such that "n-1 = 2^s * d"
var p = n - 1
var d = p / 2
var s = Math.log2(p / d);
return s;
}
Once you start fixing the errors that crash there are a few other big problems. For example your fermat() potentially runs for ever:
for (var t = 0; t = numTrials; t++) {
Should be:
for (var t = 0; t == numTrials; t++) {
= sets t to numTrails for every loop
I think you should start at the beginning, put all your functions together and all you other logic code that calls the functions together so you can see what's going on.
Related
I am stuck in the sumAll exercise from the Fundamentals 4 portion of the Odin Project. I managed to pass the test in which I need the result to be ‘ERROR’. However, I cannot figure out the correct code to pass the other tests. Where did I go wrong?
This is the exercise:
const sumAll = require(’./sumAll’)
describe(‘sumAll’, function() {
it(‘sums numbers within the range’, function() {
expect(sumAll(1, 4)).toEqual(10);
});
it(‘works with large numbers’, function() {
expect(sumAll(1, 4000)).toEqual(8002000);
});
it(‘works with larger number first’, function() {
expect(sumAll(123, 1)).toEqual(7626);
});
it(‘returns ERROR with negative numbers’, function() {
expect(sumAll(-10, 4)).toEqual(‘ERROR’);
});
it(‘returns ERROR with non-number parameters’, function() {
expect(sumAll(10, “90”)).toEqual(‘ERROR’);
});
it(‘returns ERROR with non-number parameters’, function() {
expect(sumAll(10, [90, 1])).toEqual(‘ERROR’);
});
});
My code:
const sumAll = function(a, b) {
const arr = [];
if (a < b) {
while (a <= b) {
arr.push(a++);
}
} else if (b < a) {
while (b <= a) {
arr.push(b++);
}
} else {
arr.push(a);
}
if (a < 0 || b < 0) {
return “ERROR”;
} else if (typeof a !== NaN || typeof b !== NaN) {
return “ERROR”;
}
return arr.reduce((a, b) => a + b);
}
module.exports = sumAll
I made in this way:
const sumAll = function (x, y) {
if (x > 0 && y > 0 && typeof x === 'number' && typeof y === 'number') {
var valorx = x;
var valory = y;
var total = 0;
if (x < y) {
for (var i = valorx; i <= valory; i++) {
total += i;
}
return total;
} else if (x > y) {
for (var i = valory; i <= valorx; i++) {
total += i;
}
return total;
}
} else {
return 'ERROR'
}
}
module.exports = sumAll
this how it work for me
const sumAll = function (startN, endN) {
//create variable to store total sum
let sum = 0;
check if input parameter in number:
if (typeof startN != "number" || typeof endN != "number") return "ERROR";
check if input numbers greter than 0:
else if (startN < 0 || endN < 0) return "ERROR";
and last check is, if last number greater than the first number then initial number will be the last number otherwise start number will be the initial:
else if (startN < endN) {
for (i = startN; i <= endN; i++) {
sum += i;
}
} else {
for (i = endN; i <= startN; i++) {
sum += i;
}
}
then return sum:
return sum;
};
you can make all these in one check but this are more readable.
That's how i did it. Quite similar but i avoided using for loops.
const sumAll = function(n,m) {
if (n<0 || m<0 || typeof(m) !== 'number' || typeof(n) !== 'number'){
return 'ERROR'
}else {
if(n<m){
n1 = n
n2 = m
}else{
n1 = m
n2 = n
}
return (n1+n2)*(n2/2)}
};
I first checked whether the input is valid, then decided the values of the two variables depending on which is bigger and finally calculated the sum.
So i am doing Euler problems, and i got to problem asking to find 10001st prime number. i did it like this. From what i can see it has O n^2. Codepen didnt like the time it took and thought it was an infinite loop, had to run on another compiler, my question is there anyway to improve this?
isPrime=(num)=>{
if(num<=1){
return false;
}
for(let i=2;i<num;i++){
if(num%i == 0){
return false;
}
}
return true;
}
findPrime=()=>{
let count=0;
let number = 1;
let prime=0;
while(count != 10001){
let result = isPrime(number);
if(result === true){
count++;
prime = number;
}
number++;
}
return prime;
}
Takes around 1/60 time in node.js and around 1/140 here in Chrome comparing to your original without additional optimisations on my machine, but has a bit more complex setup...
var primes = [2, 3]; // lets start with some basic
function myPrimes(no, mapSize) {
var nonPrimeMap = {};
var pos = 0;
var pos2 = 4;
while (pos < no) {
var s = primes[pos++];
for (var x = s * 2; x < mapSize; x += s) nonPrimeMap[x] = 1;
do {
if (nonPrimeMap[pos2]) pos2++;
else {
primes.push(pos2++);
break;
}
} while (true);
}
}
function runTest() {
var a = new Date();
myPrimes(9999, 110000);
var c = new Date();
console.log(primes[primes.length - 1], c - a); // My test timespans in ms
var b = findPrime();
a = new Date();
console.log(b, a - c); // Your
}
isPrime = (num) => {
if (num <= 1) {
return false;
}
for (let i = 2; i < num; i++) {
if (num % i == 0) {
return false;
}
}
return true;
};
findPrime = () => {
let count = 0;
let number = 1;
let prime = 0;
while (count != 10001) {
const result = isPrime(number);
if (result === true) {
count++;
prime = number;
}
number++;
}
return prime;
};
runTest();
Devise an algorithm to receive a positive number, n, and output all prime numbers that are smaller than n
and have a digit 7. For example, if n is 100, the program should output 7, 17, 37, 47, 67, 71, 73, 79, and 97.
Program freezes without giving output
function P6() {
var n = parseInt(prompt("Please enter a value"));
for (var i = 2; i <= n; i++) {
if (prime(i) && has7(i)) {
alert(i);
}
}
}
function prime(s) {
var flag = true;
var d = 2;
while (flag == true && d <= s / 2) {
if (s % d == 0) {
flag = false;
}
d = d++;
}
return flag;
}
function has7(v) {
var has7 = false;
var length = Math.log(v) + 1;
for (var i = 1; i <= length; i++) {
var last = v % 10;
if (last == 7) {
has7 = true;
}
v = v % 10
}
return has7;
}
This line is wrong:
d = d++;
d++ is a post-increment, it increments the variable but evaluates to the old value. So when you assign the result back to the variable, it sets it back to the original value. As a result, you have an infinite loop.
It should be either:
d = d + 1;
or just:
d++;
Another error is:
v = v % 10;
This is supposed to divide v by 10, but it's just setting v to its last digit. It should be:
v = Math.floor(v / 10);
In the code below, I've simplified all your loops. Rather than setting variables and continuing the loops, they return as soon as the loop can determine the answer. If the loop ends without returning, they return the opposite value.
function P6() {
var n = parseInt(prompt("Please enter a value"));
for (var i = 2; i <= n; i++) {
if (prime(i) && has7(i)) {
console.log(i);
}
}
}
function prime(s) {
for (var d = 2; d <= s / 2; d++) {
if (s % d == 0) {
return false;
}
}
return true;
}
function has7(v) {
while (v != 0) {
var last = v % 10;
if (last == 7) {
return true;
}
v = Math.floor(v / 10);
}
return false;
}
P6();
I am working on this kata https://www.codewars.com/kata/count-9-s-from-1-to-n/train/javascript
and i have written this code for it, but its not working. This question is similar to this one Count the number of occurrences of 0's in integers from 1 to N
but it is different because searching for 9's is practically very different to searching for 0's.
think part of the problem with this code is that it takes too long to run...
any advice appreciated!
function has9(n) {
var nine = [];
var ninearr = n.toString().split('');
for (var j = 0; j < ninearr.length; j++) {
if (ninearr[j] == '9') {
nine.push(ninearr[j]);
}
}
return nine.length;
}
function number9(n) {
var arr = [];
var arrnew = [];
for (var i = 0; i <= n; i++) {
arr.push(i);
}
for (var l = 0; l < arr.length; l++) {
arrnew.push(has9(l));
}
var sum = arrnew.reduce((a, b) => a + b, 0);
return sum;
}
Why not a regex based solution? (Too slow as well?)
const count9s = num => num.toString().match(/9/g).length
console.log(count9s(19716541879)) // 2
console.log(count9s(919191919191919)) // 8
console.log(count9s(999)) // 3
console.log(count9s(999999)) // 6
I have taken the above hint and completely re written the code, which I now feel should work, and it does for most inputs, but codewars is saying it fails on some of them. any ideas why?
function nines(n){
if(n>=100){
var q= Math.floor(n/100);
var nq= q * 20;
var r = (n%100);
var s = Math.floor(r/9);
if (r<=90){
return s + nq;
}
if (r == 99){
return 20 + nq;
}
if (90 < r < 100 && r!= 99){
var t = (r-90);
return nq + s + t;
}
}
if (n<100){
if (n<=90){
var a = Math.floor(n/9);
return a ;
}
if (n == 99){
return 20
}
if (90 < n < 100 && n!= 99){
var c = (n-90);
return 10 + c;
}
}
}
=== UPDATE ===
I just solved your kata using
function number9Helper(num) {
var pow = Math.floor(Math.log10(num));
var round = Math.pow(10, pow);
var times = Math.floor(num / round);
var rest = Math.abs(num - (round * times));
var res = pow * (round==10 ? 1 : round / 10) * times;
if (num.toString()[0] == '9') res += rest;
if (rest < 9) return res;
else return res + number9Helper(rest);
}
function number9(num) {
var res = number9Helper(num);
res = res + (num.toString().split('9').length-1);
return res;
}
== Function below works but is slow ===
So, could something like this work for you:
for (var nines=0, i=1; i<=n; i++) nines += i.toString().split('9').length-1;
Basically, there are many way to achieve what you need, in the end it all depends how do you want to approach it.
You can test it with
function nines(n) {
for (var nines=0, i=1; i<=n; i++) nines += i.toString().split('9').length-1;
return nines;
}
function number9(n) {
if (n < 8) {
return 0
};
if (n === 9) {
return 1
};
if (n > 10) {
let str = ''
for (let i = 9; i <= n; i++) {
str += String(i)
}
return str.match(/[9]/g).length
}
}
var userNumber = parseInt(prompt("What number would you like to have factored?"));
var factoring = function(n) {
var m = n;
var o = n;
for(i = 2; i < n/2; i++) {
if (m % i === 0 && o % i === 0) {
var p = 0;
while (n % i === 0) {
n = n / i;
p++;
}
n = m;
o = o / i;
if (p > 1) {
console.log(i + "^" + p);
}
else {
console.log(i);
}
}
else {}
}
};
factoring(userNumber);
When I feed the above code an input that's large and relatively very composite, it gives wrong answers. 900, for example gives:
2^2
3^2
5^2
6^2
The first three rows are accurate, but the 6^2 is just a repeat of the 2 and the 3. How do I make the 6^2 not show, as well as solving other similar problems like the extra 25 given when you input 1000?
P.S. I am aware that this code takes more work than is necessary, but I would still rather make it work more or less as is than replace it with some other method entirely.
You are resetting n to its original value by doing n=m;. This is the reason, why you get non-prime factors. Also, you don't need o. Also, you need to run your outer loop till m/2 + 1, not just till m/2. See the corrected version below.
var userNumber = parseInt(prompt("What number would you like to have factored?"));
var factoring = function(n) {
var m = n;
var o = n;
for(i = 2; i < m/2 + 1; i++) {
if (n % i === 0) {
var p = 0;
while (n % i === 0) {
n = n / i;
p++;
}
if (p > 1) {
console.log(i + "^" + p);
}
else {
console.log(i);
}
}
else {}
}
};
factoring(userNumber);