I want to know if it is possible to make a number the opposite to what it currently is using JavaScript. ie if a number is 400. Is it possible to make it -400, similar if a number is -400 is it possible to make it 400?
This is not jQuery!
Just multiply it by -1.
num = "400"
console.log(-num);
Core JS,
function opposite(number) {
return(-number);
}
As the shorter solution from http://www.codewars.com/
In one Line..
const opposite = number => -number;
function opposite(number) {
let result;
if (!isNaN(Math.sign(number))) {
result = number * (-1);
}
return result;
}
const opposite(num) {
return num * -1;
}
What I also realized was that if you just:
const opposite(num) {
return -num;
}
The negative can be used to create a positive when returning the num because if it is a negative integer turning into a negative number the two negatives cancel each other out into a positive.
To shorten the code you can also use:
const opposite = num => -num;
All ways work. It's all in how fast you want the solution. The faster the better. The most simple way a code can be written the better.
I really liked #KRESH 's answer because it made me find out what Math.sign() was. The whole adventure of figuring out what his code did was fantastic. I wonder what it could be best used for. That's what's going to be fun figuring out next.
Related
I would like to return all possible combinations for a string while maintaining the proper order of everything and avoiding duplicates. The reason for this? I'd like to make answers for some Japanese quizzes more flexible by allowing a mix of kana and kanji. As such, I require all possible combinations for comparison against the user's answer.
This is the current syntax of the function: (located here)
Genki.getAlts('{月曜日}と{水曜日}と{金曜日}に{日本語}のクラスがあります', 'げつようび|すいようび|きんようび|にほんご');
The text within curly braces is the text that will be replaced by the alternative text in the second argument, I'll refer to these simply as replacements. HOWEVER, the alternate text should ONLY replace the same index. That is:
月曜日 can only be replaced with げつようび
水曜日 can only be replaced with すいようび
and so on...
To give a simple example of what I'd like to achieve. Say I have the following:
Genki.getAlts('...{A}...{B}...', '1|2', true);
I'd like it to return all combinations, such as below.
'...1...{B}...'
'...1...2...'
'...{A}...2...'
'...{A}...{B}...'
The current implementation works well with 2-7 given replacements, but when given more than 8, the total combo coverage begins to drop. The total amount of combinations can be calculated using this formula: Math.pow(2, 8), which would return "256" combinations for 8 replacements, but currently getAlts() is only returning 234 combos, which means we're missing 22, only giving us 91% combo coverage.
So that is where I'm currently stuck. You can review the current code via the links below. (and yes, it's rather hackish) Being self-taught I tried my best to get as many combos as possible, but I'm afraid that my skill with mathematics isn't that good. I'm sure there's a much simpler way of going about this and I'm just overthinking it.
code: Genki.getAlts()
test page: lesson-4/workbook-6 || page source (the console will show all current combinations)
As an example of the current algorithm's failure, open your console, and you should see a warning for the last problem, saying something along the lines of:
234/256 (91.40625% combo coverage for 8 replacements; 22 missing combos
Code for this problem:
Genki.getAlts('{1:私}はきのう{学校}で{1:写真}を{1:撮}りました。{2:私}は{家}でも{2:写真}を{2:撮}りました。', 'わたし|がっこう|しゃしん|と|わたし|いえ|しゃしん|と', true);
and a much simpler one with 10 replacements for performing test cases in the console:
Genki.getAlts('{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}', '1|2|3|4|5|6|7|8|9|10', true)
Is there any possible and simplistic way of returning all the combinations for a string regardless of how many replacements are specified? While I do know how many combinations there are, using Math.pow(2, n), I'm unsure of how to properly get them all.
I am open to hearing about existing algorithms or frameworks for achieving this.
PS: as things are, the algorithm works fine for 2-7 replacements, with very few problems ever reaching or going above this threshold. However, when they do, there's a chance that the user's answer will erroneously be marked wrong and I'd like to avoid this. The simplest solution would obviously be to avoid ever breaking 7, but that's not always possible, and furthermore, the current way I'm achieving this isn't optimal, so I would like to optimize it as well.
You can solve this problem using binary math. Here's an approach that generates the array of strings:
function getAlts(str, alt) {
var subs = alt.split('|');
var length = subs.length;
var permutations = Math.pow(2, length);
var results = [];
for (var i = 0; i < permutations; ++i) {
var bitIndex = 0;
var result = str.replace(/\{(.*?)\}/g, function (match, p1) {
var subIndex = bitIndex++;
var bit = length - 1 - subIndex;
return ((1 << bit) & i) ? subs[subIndex] : p1;
});
results.push(result);
}
return results;
}
console.log(getAlts('...{A}...{B}...', '1|2'));
Or if you're able to use ES6 (ECMAScript 2015), you can write a generator function to use less memory:
function* getAlts(str, alt) {
var subs = alt.split('|');
var length = subs.length;
var permutations = Math.pow(2, length);
for (var i = 0; i < permutations; ++i) {
var bitIndex = 0;
var result = str.replace(/\{(.*?)\}/g, function (match, p1) {
var subIndex = bitIndex++;
var bit = length - 1 - subIndex;
return ((1 << bit) & i) ? subs[subIndex] : p1;
});
yield result;
}
}
var results = getAlts('{A}{B}{C}{D}{E}{F}{G}{H}{I}', '1|2|3|4|5|6|7|8|9');
var total = 0;
for (var result of results) {
console.log(result);
total++;
}
console.log('total:', total);
I'm using this BigInteger.js for some calculations:
let myBigInt = bigInt(20).pow(200) // gets 160693804425899027554196209234116260252220299378279283530137600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
I'd like to apply the logarithm to the big integer but in the docs I could not find any matching function. How can I implement a log(baseN, valueX) function for the BigInteger.js library?
Note: let myLogarithm = myBigInt.log(baseN) is not a valid implementation.
Note: After a lot of try&error I did found a working solution my own and I will post it here because I'm pretty sure there are a few more people then me that also gots faced with the same issue right there. So I hope, I could help :)
Have a look at wikipedia, as I did because theres a very nice article about baseConversion.
Below you can find a function for Math.log(base, value) that is able to calculate the log(base) from a value.
Math.log = (function() {
var log = Math.log;
return function(base, n) {
return log(n)/(base ? log(base) : 1);
};
})();
To calculate the logarithmToBaseN for bigInt-values just use this line of code:
let logarithmToBaseN = (myBigInt.toString().length * Math.log(baseN, 10) + Math.log(baseN, parseFloat("0." + myBigInt))) - 1);
Edit: This soltuion is a tiny workaround bacause parseFloat("0." + myBigInt) converts a big value like 100000 to a really small one like 0.100000,... what causes that it will be in integer precision.
According to #Jonas W's comment: The solution is very accurate for lower bases like (5, 10, ...) combined with low values like 10, 1000, 100000 - but for really big values like bigInt(20).pow(200) is it not.
Note: Using parseFloat (IEEE 754 double precision floating-point) means, you have a maximum of 52 bits of precision, which is a bit more than 15 decimal places. After that - the accuracy will be killed.
Note: For really big values bigInt(20).pow(200) combined with really big Bases like 100*(and more) it seems to be pretty accurate again.
Greetings, jonas.
I'm trying to get random number between 0 and Array.length.
I have this:
getRandom() {
const cars = Object.keys(this.index);
const randomInt = Math.floor(Math.random() * cars.length);
return cars[randomInt];
}
I ran this few times and found a 0 in one of the results from getRandom(). There is not key in my this.index object named 0.
Is my math function wrong?
UPDATE
After reading the comments, and I know the getRandom() is not wrong. I also have reset() function if you guys can look at it.
reset() {
const cars = Object.keys(this.index);
let i = cars.length;
while (i--) {
this.index[cars[i]] = 0;
}
}
Is it possible I'm adding a new key 0 at this.index object?
I can't see an actual problem here.
Object.keys will turn your named keys into numbers (look here https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Object/keys), this numbers starts with 0.
So your function, as you wrote yourselv, will return an:
random number between 0 and Array.length
You can make use of this existing solution.
Generating random whole numbers in JavaScript in a specific range?
And pass 0 and array.length as params.
I wonder what you're seeing, but we're all lacking context here, so I made a little example to try the function to see the problem with my own eyes and it does not seem to have the problem you described.
Try it for yourself here - and maybe it's the data you're running the method on that is the problem?
When you run a huge sum in JS it comes out with something like : 1.0328135768135768e+21.
Is there a way to make it output a pure integer, even if it is very long?
Thanks.
The .toString() method seems to do the trick. Sort of:
1.0328135768135768e+21.toString("10");
// "1032813576813576802460"
1.0328135768135768e+50.toString("10")
// "103281357681357664662886440420862446808642642662440"
Note that (as shown above) because of JS's handling of floating point numbers you don't just get the digits you specified with zeros on the end.
If you wanted all zeros on the end you could always format it yourself:
function formatNumber(n) {
var s = n + "",
a = s.split("e");
if (a.length === 1)
return s;
s = a[0].replace(/\./,"");
s += (new Array(+a[1] - s.length + 2).join("0"));
return s;
}
Demo: http://jsfiddle.net/HLQQ9/ (Note: not tested thoroughly at all, just a half-baked idea I hacked together to give you a starting point.)
Or there are several big number libraries around.
I have a javascript that calculates the percentage from two fields (retail and network) and then dumps that percentage into another field (markup).
As I am relatively new to the world of JS I have ended up reusing the code for several rows of fields. This goes against DRY and KISS principles so I was wondering if you could give me some input on how to optimise my code so that it can handle any two fields and then dump a value to a third field.
Here is a screenshot of my form segment that is using it.
http://i.imgur.com/FHvDs.png
Here is my code I am using, I have had to reuse it four times and place the code in four functions e.g. (percentage1, percentage2, percentage3, percentage4) each one of these functions deals with a row of fields show in the screenshot.
function percentage1()
{
//the dividee
x = document.getElementById('tariff_data');
//the divider
y = document.getElementById('network_data');
//if the first value is lower than the second, append a "-" sign
if (x.value < y.value)
{
z = "-"+(x.value/y.value)*100;
document.getElementById('markup_data').value = z;
}
//not a negative percentage
else
{
z = (x.value/y.value)*100;
document.getElementById('markup_data').value = z;
}
}
function percentage2()
{
//the dividee
x = document.getElementById('tariff_rental');
//the divider
y = document.getElementById('network_rental');
//if the first value is lower than the second, append a "-" sign
if (x.value < y.value)
{
z = "-"+(x.value/y.value)*100;
document.getElementById('markup_rental').value = z;
}
//not a negative percentage
else
{
z = (x.value/y.value)*100;
document.getElementById('markup_data').value = z;
}
}
etc etc....
These functions are called using the onchange HTML attribute
Also when I divide by a decimal number it gives the wrong value, any Ideas how to make it calculate the correct percentage of a decimal number?
My code also gives out these strange outputs:
NaN , Infinity
Thanks
Rather than optimization, let's focus on correctness first =)
Note that the HTMLInputElement.value property has type "string", so your arithmetic operators are doing implicit type conversion which means you are likely often doing string concatenation instead of the numeric operations you expect.
I strongly recommend explicitly converting them to numbers first and checking for invalid input, also, don't forget to declare your variables first using var so they don't potentially clobber globals, e.g.:
var x = Number(document.getElementById('tariff_data'));
var y = Number(document.getElementById('network_data'));
if (!isFinite(x) || !isFinite(y)) {
// Handle non-numerical input...
}
You can also use the parseFloat function if you prefer, e.g.:
var x = parseFloat(document.getElementById('tariff_data'), 10);
I highly recommend doing some formal learning about the JavaScript language; it is full of pitfalls but if you stick to the "good parts" you can save yourself a lot of hassle and headache.
With regard to DRYing your code out; remember that you can:
Pass parameters to your functions and use those arguments within the function
Return values using the return keyword
In your case, you've got all your multiplication code repeated. While trying to fix the string vs. number problems maerics has already mentioned, you could do something like this:
// We're assuming 'dividee' and 'divider' are numbers.
function calculatePercentage(dividee, divider) {
var result;
// Regardless of the positive/negative result of the calculation,
// get the positive result using Math.abs().
result = Math.abs((dividee.value / divider.value) * 100);
// If the result was going to be negative...
if (dividee.value < divider.value) {
// Convert our result to negative.
result = result * -1;
}
// Return our result.
return result;
}
Then, in your percentage functions, you can just call this code like so:
function percentage1() {
var tariff, network, markup;
tariff = parseFloat(document.getElementById('tariff_data').value, 10);
network = parseFloat(document.getElementById('network_data').value, 10);
markup = document.getElementById('markup_data');
markup.value = calculatePercentage(tariff, network);
}
Obviously, you could take this further, and create a function which takes in the IDs, extracts the values from the elements etc., but you should try and build that yourself based on these tips.
Maerics also makes a very good point which you should take note of; learn more about the Good Parts of JavaScript. Douglas Crockford's book is excellent, and should be read and understood by all JS developers, IMHO.
Hope this helps you clean your code up!