Javascript - Structure for a look-up table - javascript

I am not quite sure if the wording in the title accurately describes what I am looking to do, allow me to explain:
Suppose in a game, you get different type of points from leveling up.
But the amount of points of each type you get each level can be arbitrary.
For example,
I get 3 offensive point for every 2 level.
But I get 2 defensive point at level 2, 4, 5, and 6 say.
And perhaps 1 supportive point at every level except the first.
Now here's what I've done:
//Suppose I have my hero
var Sylin = new Hero();
Sylin.Level = 5;
//My goal is then to set
// Sylin.OffensivePoint to 6
// Sylin.DefensivePoint to 6
// Sylin.SupportivePoint to 4
Sylin.prototype.OffensivePoint = function() {
return 3*Math.floor(this.Level/2);
};
Sylin.prototype.DefensivePoint = function() {
var defPoint = 0;
for(var i=2; i <= this.Level; i++) {
//maximum level being 6
if(i==2 || i >= 4) {
defPoint += 2;
}
}
return defPoint;
};
Sylin.prototype.SupportivePoint = function() {
return this.Level - 1;
};
It's all fine and dandy, but if the maximum level is extended, the points lists will be updated and then it gets really clumsy, especially if I have things like:
2 points every 3 level, but 3 point on the 9th and 13th level or something apparently lacking in pattern so I can't always do it like what I have for OffensivePoint().
What I have in mind for this type of problems in general is a structure like so:
Level TotalPoint
. . 1 . . . . . a
. . 2 . . . . . b
. . 3 . . . . . c
. . 4 . . . . . d
. . 5 . . . . . e
and so on until the maximum level
In the code, I could then perhaps do:
Sylin.prototype.talentPoint = function() {
return readTalentPointTable(this.Level); //?
};
But then this can still get quite convoluted if there's 20 level with 5 different types of points you can get, say :/
.
.
EDIT
Ok, so I could do something like:
var OffensivePointTable = [0,0,2,2,4,6,8,8,8,10,12];
function getOffensivePoint(level) {
return OffensivePointTable[level];
}
Would it be easier if I store the data by the level in which a point is increased, or by the running total as above?
.
.
EDIT 2
Ok, can I perhaps reverse the order of the structure to look at the type first, then level?
var theTable = {
o: [0,1,0,1,1,0,0,0],
d: [0,0,2,0,2,0,2,0],
s: [0,1,2,3,4,5,6,7]}
//then your CalculateStats:
Sylin.prototype.CalculateStats = function() {
this.offensivePoint = 0;
for(var i=1; i<= this.Level; i++) {
this.offensivePoint += theTable[o][i];
}
}

You could use an object to store the amount of points to increment at each table (I didn't use your exact numbers, but you get the idea):
var LevelPoints = {
'1': {
o: 1,
d: 2,
s: 1
}
'2': {
o: 3,
d: 1,
s: 1
}
'3': {
o: 1,
d: 1,
s: 0
}
'4': {
o: 2,
d: 3,
s: 1
}
//etc.
}
For example, to access the offensive point increase at level 2, use LevelPoints['2'].o.
This requires a lot of typing I suppose, but sometimes just having all the data there makes things easier. Making your code readable to you and easy to change is always nice. It's also useful as a quick reference—if you're wondering how many offensive points will be gained at level 6, you can know immediately. No need to decipher any procedural code. Of course, this is personal preference. Procedural approaches are faster and use less memory, so it's up to you whether that's worth it. In this case the difference will be negligible, so I recommend the data-driven approach.
Also, note that I used var to set this object. Because it can be used by all instances of the Sylin constructor, setting it as an instance variable (using this) is wasteful, as it will create the object for every instance of Sylin. Using var lets them all share it, saving memory.
Alternately, you could store the running total at each level, but IMO this requires more effort for no good reason. It would take less of your time to write a function:
Sylin.prototype.CalculateStats = function() {
this.OffensivePoint = 0;
this.DefensivePoint = 0;
this.SupportivePoint = 0;
for (var i = 1; i <= this.Level; i++) {
this.OffensivePoint += LevelPoints[i].o;
this.DefensivePoint += LevelPoints[i].d;
this.SupportivePoint += LevelPoints[i].s;
}
}
Then just run this function any time the user changes the level of the character. No need to pass the level, as the function will already have access to the this.Level variable.

Why not store the points in an array of objects -
var pointsTable = [{offensivePionts: 1, defensivePoints: 1}, {offensivePoints: 1, defensivePoints: 2}]; //extend for any level
And then just get return points by referencing the corrent property -
function getOffensivePoints(level) {
return pointsTable[level]['offensivePoints'];
}
You can easily extend the datastructure with methods like addLevel etc.

Sure you could always create an hardcoded array of all points, however you could also simply hardcode the exceptions and stick with an algorithm when you can.
Just an idea... that would require your hero to keep track of his points instead of recompiling them dynamically however, but that's probably a good thing.
//have a map for exceptions
var pointExceptionsMap = {
'9': {
off: 3 //3 points of offense on level 9
}
};
Sylin.prototype.levelUp = function () {
var ex = pointExceptionsMap[++this.level];
//update offense points (should be in another function)
this.offense += (ex && typeof ex.off === 'number')?
ex.o /*exception points*/:
this.level % 2? 0 : 2; //2 points every 2 levels
};
Then to level up, you do hero.levelUp() and to get the points hero.offense. I haven't tested anything, but that's the idea. However, if you require to be able to set the level directly, you could either have a setLevel function that would call levelUp the right amount of times but, you would have to use a modifier to allow you leveling down as well.
You could also use my current idea and find an efficient way of implementing exceptionnal algorithms. For instance, you could still dynamically compile the number of offense points, and then add or remove points from that result based on exceptions. So if you need 2 points every 2 levels, but 3 for the level 9, that means adding 1 additionnal point to the compiled points. However, since when you reach higher levels, you wan to retain that exception, you would have to keep track of all added exception points as well.
EDIT: Also, nothing prevents you from using a function as a new exceptionnal algorithm instead of a simple number and if you plan to make the algorithms configurable, you can simply allow users to override the defaults. For instance, you could have a public updateOffense function that encapsulates the logic, so that it can be overriden. That would be something similar to the Strategy design pattern.
EDIT2: Here's a complete example of what I was trying to explain, hope it helps!
var Hero = (function () {
function Hero() {
this.level = 0;
this.stats = {
off: 1,
def: 0
};
}
Hero.prototype = {
statsExceptions: {
'3': {
off: 3 //get 3 points
},
'6': {
def: function () {
//some algorithm, here we just return 4 def points
return 4;
}
}
},
levelUp: function () {
++this.level;
updateStats.call(this, 1);
},
levelDown: function () {
updateStats.call(this, -1);
--this.level;
},
setLevel: function (level) {
var levelFn = 'level' + (this.level < level? 'Up' : 'Down');
while (this.level !== level) {
this[levelFn]();
}
},
statsFns: {
off: function () {
return (this.level % 2? 0 : 2);
},
def: function () {
return 1;
}
}
};
function updateStats(modifier) {
var stats = this.stats,
fns = this.statsFns,
exs = this.statsExceptions,
level = this.level,
k, ex, exType;
for (k in stats) {
if (stats.hasOwnProperty(k)) {
ex = exs[level];
ex = ex? ex[k] : void(0);
exType = typeof ex;
stats[k] += (exType === 'undefined'?
/*no exception*/
fns[k].call(this) :
/*exception*/
exType === 'function' ? ex.call(this) : ex) * modifier;
}
}
}
return Hero;
})();
var h = new Hero();
console.log(h.stats);
h.setLevel(6);
console.log(h.stats);
h.setLevel(0);
console.log(h.stats);
h.levelUp();
console.log(h.stats);
//create another type of Hero, with other rules
function ChuckNorris() {
Hero.call(this); //call parent constructor
}
ChuckNorris.prototype = Object.create(Hero.prototype);
//Chuck gets 200 offense points per level y default
ChuckNorris.prototype.statsFns.off = function () {
return 200;
};
//Not exceptions for him!
ChuckNorris.prototype.statsExceptions = {};
console.info('Chuck is coming!');
var c = new ChuckNorris();
c.setLevel(10);
console.log(c.stats);

Related

Testing conditions on a constantly changing object in javascript

I'm trying to create a browser game. The game state is stored in an object with multiple layers.
let State = {
points: 0,
health: 50,
currentLocation: {x: 5, y: 55},
inventory: { bread: 8, water: 33, money: 20 }
abilities:
charisma:5,
perseverance: 3,
speed: 8
}
buildings {
bakery: { location: {x: 23, y: 41}, unlocked: 1, visited: 1},
homestead: { location: {x: 3, y: 59}, unlocked: 0, visited: 0},
forge: { location: {x: 56, y: 11}, unlocked: 1, visited: 0}
}
}
I want to be able to control the game logic based on the current values of State.
Some cases are very simple
if(State.health == 0) { Game.die(); }
Most cases are much more complex
if(State.buildings.bakery.unlocked == 1) {
// calculate player's distance to bakery
let dX = Math.abs(State.buildings.bakery.location.x - State.currentLocation.x)
let dY = Math.abs(State.buildings.bakery.location.y - State.currentLocation.y)
let d = DX + dY;
if(State.inventory.bread == 0 && d < State.inventory.abilities.speed) {
Game.die();
}
}
What is the best way to achieve something like this? Looping over all the conditions seems to be a needless use of resources. I've looked into getters, setters and Proxy but don't really know what I'm doing! Ideally I'd only want to only check the logic when a relevant part of State changes.
I'd only want to only check the logic when a relevant part of State changes.
Then use a getter and setter like this:
let State = {
buildings: {
bakery: {
_unlocked: false,
get unlocked() {
return this._unlocked;
},
set unlocked(value) {
this._unlocked = value;
if (value == true) {
console.log("Calculating player's distance to bakery ...");
}
}
}
}
}
State.buildings.bakery.unlocked = true;
// Calculating player's distance to bakery ...
The use of the _unlocked variable is because if you didn't, the first time unlocked is accessed, it will trigger its own getter recursively until you get a stack overflow error.
Here's what I've ended up doing...
const state = {
_data:{}, // object in which the data is actually stored
get:(path) => { // safely get the value or return undefined
return path.split('.').reduce((o,i)=>(o||{})[i], state._data)
},
set:(fullpath,value,silent=0) => { // safely set the value
function cycle(obj,path,value) {
let i = path[0]
if(path.length==1) { // if this is the end of the path
obj[i] = value; // change the value
if(!silent) { Pubsub.publish('state.'+fullpath, value) ; } // and publish the event
} else { // if this is not the end of the the path
if(typeof obj[i] !== 'object') { obj[i] = {} } // create this part of the path if it doesn't exist
cycle(obj[i],path.slice(1), value) // move on to the next part of the path
}
}
cycle(state._data,fullpath.split('.'),value)
}
Step 1: Get and set
I created two custom functions to get and set the state.
get() takes a dot notation path as a string, e.g. state.get('buildings.bakery.unlocked').
set() also takes a dot notation path as a string as well as the value, e.g. state.set('buildings.bakery.unlocked', 1).
I used some code from this thread. Using these functions means it's easy to manipulate nested properties without worrying about the dreaded TypeError.
Step 2: PubSub
The dot notation path also feeds a publish/subscribe model. I'm using PubSubJS. Calling set() also publishes an event that matches the path, e.g. state.set('abilities.strength', 5) also publishes 'state.abilities.strength'.
To monitor state changes, you simply subscribe to the relevant events:
PubSub.subscribe('state.abilities.strength', () => console.log('strength value changed'))
The published event also passes back the new value, so you can do what you want with it:
PubSub.subscribe('state.inventory.bread', (path, value) => console.log('bread value changed, you now have ' + value))
Step 3: Implement to compare
PubSub has the benefit of being a topic based system. This means you can subscribe to non-final nodes:
PubSub.subscribe('state.inventory', () => console.log('something in the inventory changed'))
PubSub.subscribe('state.inventory.water', () => console.log('water changed'))
Changing inventory.bread will trigger the first, changing inventory.water will trigger both.
This allows me to separates the game logic from the state. There's two ways to compare values...
// function to compare two values
let comparison = function () {
console.log('running comparison');
if(state.get('test.valueA') > state.get('test.valueB')) {
console.log('A is bigger than B');
}
}
// you either subscribe to both the values, and compare whenever either one changes
PubSub.subscribe('state.test.valueA', comparison)
PubSub.subscribe('state.test.valueB', comparison)
// or alternatively, if they have a shared topic, then subscribe to that
PubSub.subscribe('state.test', comparison)

Is there a way that I can dynamically pass object names to a function (as arguments) and reference properties of that object using the argument?

I am trying to get the ID from imgs in my HTML, and pass those id's (which correspond to js objects that I've created) as arguments then access certain properties of those objects inside a function.
I've tried a variety of different methods to select the id of the child element, but I still get 'undefined' when I run the function because for some reason, passing the id as the argument doesn't allow me to access the keys of that object. I'm guessing that it's because the id is a string, and "string".key won't work. However, if that's the case, is there a way to dynamically get the object names and pass them as arguments? I'm still new, so if I'm not explaining myself well I apologize, hopefully, the code makes more sense.
let peas = {
name : "peas",
attack : 5,
health : 100,
counterAttack : 10,
enemy : false
};
let broccoli = {
name : "broccoli",
attack : 5,
health : 100,
counterAttack : 10,
enemy : false
};
function battleFunction(player, computer) {
//increments playerAttack
newAttack += player.attack;
player.health -= computer.counterAttack;
//deducts attack from computer HP
if (newAttack > player.attack) {
computer.health -= newAttack;
console.log(computer.health);
} else {
computer.health -= player.attack;
console.log(computer.health);
}
if (computer.health <= 0) {
defeatedEnemies++
}
if (defeatedEnemies >= 4) {
alert("You won!");
resetGame();
}
};
$("#fightBtn").click( () => {
battleFunction($("#playerDiv").children("img").attr("id"), $("#computerDiv").children("img").attr("id"));
});
I expect $("#playerDiv").children("img").attr("id") to return 'peas' and it does. Then, I expect player.attack in the function, to work like peas.attack.
If there's just a straight up a better way to do this, I am all ears.
Thank you so much for your help!
Here is an answer to this: 'How do I convert a string to a variable name?'
First, you need a surrounding object. You can use the Window object, but it is not recommended. So, you can see here that I created a simple class that contains two properties that represent your objects "sullivan" is the player and "johnson" is the computer.
Since the Controller class wraps those variable names, then we can use the object created from the class, and use [] bracket notation to gain access to the properties like this:
ctrl[player]
Then if "player" points to the string "sullivan" we can gain access to sullivan's properties.
And you can see that internally to the class, we can access them using the this keyword:
this[player]
I've completed your example below. Let me know if you have questions:
class Controller {
constructor() {
this.newAttack = 0;
this.defeatedEnemies = 0;
this.sullivan = {
name: "Sullivan",
attack: 4,
health: 10
};
this.johnson = {
name: "Johnson",
counterAttack: 8,
health: 10
};
}
battleFunction(player, computer) {
//increments playerAttack
this.newAttack += this[player].attack;
this[player].health -= this[computer].counterAttack;
//deducts attack from computer HP
if (this.newAttack > this[player].attack) {
this[computer].health -= this.newAttack;
console.log(this[computer].health);
} else {
this[computer].health -= this[player].attack;
console.log(this[computer].health);
}
if (this[computer].health <= 0) {
this.defeatedEnemies++
}
if (this.defeatedEnemies >= 4) {
alert("You won!");
//resetGame();
}
};
}
const ctrl = new Controller();
$("#fightBtn").click(() => {
ctrl.battleFunction($("#playerDiv").children("img").attr("id"), $("#computerDiv").children("img").attr("id"));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="fightBtn">Fight!</button>
<div id="playerDiv"><img id="sullivan"></div>
<div id="computerDiv"><img id="johnson"></div>

Creating millions of Objects in Javascript

Let me be the first to say that this isn't something I normally do, but out of curiousity, I'll see if anyone has a good idea on how to handle a problem like this.
The application I am working on is a simulated example of the game Let's make a Deal featuring the Monty Hall problem.
I won't go into details about my implementation, but it more or less allows a user to enter a number of how many games they want to simulate, and then if an option is toggled off, the player of those x games won't switch their choice, while if it is toggled on, they will switch their choice every single instance of the game.
My object generator looks like this:
const game = function(){
this[0] = null;
this[1] = null;
this[2] = null;
this.pick = Math.floor(Math.random() * 3);
this.correctpick = Math.floor(Math.random() * 3);
this[this.correctpick] = 1;
for (let i=0; i<3; i++){
if ((this[i] !== 1) && (i !== this.pick)){
this.eliminated = i;
break;
}
}
}
const games = arg => {
let ret = [];
for(let i=0; i<arg; i++){
ret.push(new game);
}
return ret;
}
This structure generates an array which i stringify later that looks like this:
[
{
"0": 1,
"1": null,
"2": null,
"pick": 2,
"correctpick": 0,
"eliminated": 1
},
{
"0": null,
"1": null,
"2": 1,
"pick": 2,
"correctpick": 2,
"eliminated": 0
}
]
As sloppy as the constructor for game looks, the reason is because I have refactored it into having as few function calls as possible, where now I'm literally only calling Math functions at the current time (I removed any helper functions that made the code easier to read, in opt for performance).
This app can be ran both in the browser and in node (cross platform), but I have clamped the arg a user can pass into the games function to 5 million. Any longer than that and the process (or window) freezes for longer than a few seconds, or even potentially crashes.
Is there anything else I can do to increase performance if a huge number is given by a user? Also, if you need more information, I will be happy to supply it!
Thanks!
The obvious performance optimisation would be not to create and store 5 million objects at all, relieving memory pressure. Instead you'd create the objects on the fly only when you need them and throw them away immediately after. I'm not sure what your app does, but it sounds like you want to re-use the same game instances when evaluating results with the different options. In that case, you need to store them of course - but I'd advise to re-think the design and consider immediately evaluating each game with all possible options, accumulating only the results for each choice of options but not keeping all games in memory.
Apart from that, I'd recommend to simplify a bit:
You can drop that loop completely and use some clever arithmetic to find the eliminated option: this.eliminated = this.pick == this.correctpick ? +!this.pick : 3 - this.pick - this.correctpick;. Or use a simple lookup table this.eliminated = [1, 2, 1, 2, 0, 0, 1, 0, 0][this.pick * 3 + this.correctpick].
I'd avoid changing the type of the array elements from null (reference) to 1 (number). Just keep them as integers and initialise your elements with 0 instead.
Don't store 6 properties in your object that are completely redundant. You only need 2 of them: pick and correctpick - everything else can be computed on the fly from them when you need it. Precomputing and storing it would only be advantageous if the computation was heavy and the result was used often. Neither of this is the case, but keeping a low memory footprint is important (However, don't expect much from this).
Not sure about your implementation, but do you really need an Array?
How about only using results (see snippet)?
If it's blocking the browser that worries you, maybe delegating the work to a web worker is the solution for that: see this jsFiddle for a web worker version of this snippet.
(() => {
document.querySelector("#doit")
.addEventListener("click", playMontyHall().handleRequest);
function playMontyHall() {
const result = document.querySelector("#result");
const timing = document.querySelector("#timing");
const nOfGames = document.querySelector("#nGames");
const switchDoors = document.querySelector("#switchyn");
// Create a game
const game = (doSwitch) => {
const doors = [0, 1, 2];
const pick = Math.floor(Math.random() * 3);
const correctPick = Math.floor(Math.random() * 3);
const eliminated = doors.filter(v => v !== pick && v !== correctPick)[0];
return {
correctpick: correctPick,
pick: doSwitch ? doors.filter(v => v !== pick && v !== eliminated)[0] : pick,
eliminated: eliminated,
};
};
const getWinner = game => ~~(game.correctpick === game.pick);
// Sum wins using a generator function
const winningGenerator = function* (doSwitch, n) {
let wins = 0;
while (n--) {
wins += getWinner(game(doSwitch));
yield wins;
}
};
// calculate the number of succeeded games
const calculateGames = (nGames, switchAlways) => {
const funNGames = winningGenerator(switchAlways, nGames);
let numberOfWins = 0;
while (nGames--) {
numberOfWins = funNGames.next().value;
}
return numberOfWins;
}
const cleanUp = playOut => {
result.textContent =
"Playing ... (it may last a few seconds)";
timing.textContent = "";
setTimeout(playOut, 0);
};
const report = results => {
timing.textContent = `This took ${
(performance.now() - results.startTime).toFixed(3)} milliseconds`;
result.innerHTML =
`<b>${!results.switchAlways ? "Never s" : "Always s"}witching doors</b>:
${results.winners} winners out of ${results.nGames} games
(${((results.winners/+results.nGames)*100).toFixed(2)}%)`;
};
// (public) handle button click
function clickHandle() {
cleanUp(() => {
const nGames = nOfGames.value || 5000000;
const switchAlways = switchDoors.checked;
report({
switchAlways: switchAlways,
startTime: performance.now(),
winners: calculateGames(nGames, switchAlways),
nGames: nGames
});
});
}
return {
handleRequest: clickHandle
};
}
})();
body {
margin: 2em;
font: normal 12px/15px verdana, arial;
}
#timing {
color: red;
}
<p><input type="number" id="nGames" value="5000000"> N of games</p>
<p><input type="checkbox" id="switchyn"> Always switch doors</p>
<p><button id="doit">Play</button>
<p id="result"></p>
<p id="timing"></p>

webpack css-loader localIdent name hash length

I use webpack and css-loader, and in my css-loader config I use these options:
options: {
importLoaders: 1,
modules: true,
localIdentName: '[hash:base64:3]'
}
Just like you see, it is obvious that I desire all of my class name will have 3 characters, and after build absolutely my desire come true but there is a very big issue.
Some class names has same name! (conflict!)
for example:
._1mk { /*dev name was .home*/
color: red;
} /*line 90*/
and
._1mk { /*dev name was .news*/
color: blue;
}
This is a big issue, but when I use [hash:base64:5] everything would be ok and each class has its own hash name without any conflict.
I search this issue about 4 hours and saw all developers use number 5 as less of length of hash for their config. I don't know why! I calculate that 64 characters [a-z][A-Z][0-9][-,_] in three length can has 262144 different words, so why it can not some different names?
how can I settle this conflict? Really should I miss the number 3 ? and use 5 like others?
Finally, I find the right way, it is hash, not randomNaming function. this is made to hash so it is so obviously in short length with vast naming maybe it produces a collision. so I write my own Webpack naming function and use the variables and the function top on the Webpack config file. these are the steps of my solution:
At first, two variables for cache and queue. cache for easy accessing to LocalName and its new randomName and queue for holding variable entries that involve all new random names for avoiding a collision.
let q = [],
cache = {};
Second, we declare the randomNaming function. I know, maybe it is not very optimized but it works well. the export file is awesome without any collision.
function randomNaming(length, limit) {
let result = '',
chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_',
/*All valid chars*/
fchars = 'abcdefghjklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_';
/*All valid first chars*/
do {
if (q.length >= 52 * Math.pow(64, limit - 1) && limit >= length) {
return 'OutOfPossibility';
} else if (q.length >= 52 * Math.pow(64, limit - 1) && limit < length) {
++limit;
}
result = '';
result += fchars[Math.floor(Math.random() * fchars.length)];
for (let i = limit - 1; i > 0; --i) {
result += chars[Math.floor(Math.random() * chars.length)];
}
} while (q.includes(result));
q.push(result); /*push for avoiding collision in next time of funtion call*/
return result;
}
At Third, in css-loader scope inside of webpack config I used getLocalIdent not localIdentName.
const getLocalIdent = (loaderContext, localIdentName, localName, options) => {
var randName = randomNaming(3, 2);
if (localName.match(/^i-/i)) {
randName = `i-${randName}`;
} else if (localName.match(/^i_/i)) {
randName = `i_`;
} else {
randName = `${randName}`;
}
if (typeof cache[localName] == 'undefined') {
cache[localName] = randName;
return cache[localName];
} else {
return cache[localName];
}
};
And now all of the names are hashed and the CSS file is in minimal possible volume size. And the HTML is so lightweight.

Javascript toFixed behaviour with substraction

I'm manipulating a lot of numbers in my application. For this particular case, here is what I do : I retrieve two lists of numbers, I do an average for each of these list, then I substract the two average. To avoid average like 3.333333333333 I use .toFixed(3) on my results.
Here is what it looks like :
// I found this function somewhere on Stackoverflow
Array.prototype.average = function() {
if(this.length == 0){
return 0;
}
else{
return this.reduce(function (p, c) {
return p + c;
}) / this.length;
}
};
sumHigh = [ 10.965, 10.889, 10.659, 10.69, 10.599 ]
sumLow = [ 4.807, 3.065, 2.668, 2.906, 3.606, 4.074, 4.153 ]
// Ok normal
console.log(sumHigh.average()) // 10.760399999999999
console.log(sumLow.average()) // 3.6112857142857138
// Ok normal
console.log(sumHigh.average().toFixed(3)) // "10.760" Does the ".." has anything to do with my problem ?
console.log(sumLow.average().toFixed(3)) // "3.611"
// So here I have my two average values with no more than 3 numbers after the comma but it is not taken into account when substracting these two numbers...
// Not Ok, why 10.760 - 3.611 = 7.148999999999999 ?
console.log(sumHigh.average().toFixed(3) - sumLow.average().toFixed(3)) // 7.148999999999999
console.log(parseFloat(sumHigh.average().toFixed(3)) - parseFloat(sumLow.average().toFixed(3))) // 7.148999999999999
// Just as an example, this is working
console.log(parseFloat(sumHigh.average().toFixed(3)) + parseFloat(sumLow.average().toFixed(3))) // 14.371
console.log(parseFloat(sumHigh.average()) + parseFloat(sumLow.average())) // 14.371685714285713
Can someone explain this behaviour?
Why substraction is not working while addition is?
Ok I know I can solve my problem with :
console.log((sumHigh.average() - sumLow.average()).toFixed(3)) // "7.149"
But that doesn't explain this behaviour.
Thanks

Categories

Resources