Hey i've made a rotation function in Javascript for rotating some 2D vector(point).
The Y output of the function works as expected, however the X value is outputting some crazy number, can anyone point out the floor in my logic?
Vector2.prototype.rotate = function(degrees){
var angle = degrees * TO_RADIANS; //Convert to radians.
var x = (this.getX() * Math.cos(angle)) - (this.getY() * Math.sin(angle));
var y = (this.getX() * Math.sin(angle)) + (this.getY() * Math.cos(angle));
return new Vector2(x,y);
};
Inputting Vector(1,0) into this function with a rotation of 90 degrees outputs 6.someDecimalPlaces e-17; which is obviously incorrect.
The outputted Y value however works as expected and returns 1.
Thanks in advance
The "6.someDecimalPlaces e-17" you're seeing is due to Javascript's handling of floating point numbers. What you're seeing is a rounding error in converting back from binary floating point to decimal. There's no easy fix for this although there are libraries that attempt to overcome the problem.
If you want rounded numbers for pixel perfect CSS manupilation you're best bet is to round the numbers coming out of this function or cast them to integer.
Related
I'm building an app that displays the weather and converts the current temp from Fahrenheit to Celsius. For some reason, when the conversion takes place, the math isn't coming out right. Oddly, after clicking the button 5 - 6 times, it starts working correctly.
My best guess is that I'm doing something wrong with parseInt() or maybe a variable isn't being updated.
Thoughts?
function toggleUnits(){
if(wUnit.innerHTML == "C"){
var oldTemp = parseInt(wTemp.innerHTML, 10),
newTemp = oldTemp * 9 / 5 + 32;
wTemp.innerHTML= newTemp;
wUnit.innerHTML = "F";
unitToggle.innerHTML ="Switch to Celsius";
}else{
var oldTemp = parseInt(wTemp.innerHTML, 10),
newTemp = (oldTemp-32) * 5 / 9;
wTemp.innerHTML= newTemp;
wUnit.innerHTML = "C";
unitToggle.innerHTML ="Switch to Fahrenheit";
}
}
CodePen: https://codepen.io/abenjamin/pen/ZojJLq
It is helpful to scale up your decimal values by a consistent multiplier and represent all numbers as integers. For example, use 806 degrees instead of 80.6 degrees (multiply by 10) for your temperature calculations. This is to avoid the nuances with floating-point math. In JavaScript we only have the floating-point data type for numeric values, but luckily integer math under the floating-point data-type is exact. Therefore scaling up decimal values to integers (e.g., 2550 degrees instead of 25.50 degrees ) resolves the issue.
For example (converting from fahrenheit to celsius):
console.log((80.6-32) * 5 / 9); // outputs 26.999999999999996
Corrected with:
console.log((806-320) * 5 / 9 / 10 ); // outputs 27
The reason your calculator works correctly sometimes but not other times is because the temperature API sometimes returns integers, but other times returns decimal values.
I wouldn't recommend using parseInt to resolve this issue because it will round decimal values and you'll lose precision.
I would like to calculate the distance between two degree values. I know that I could use this if the points just where on one axis:
var dist = Math.abs( x1 - x2 );
...but the problem with degrees is, that they can either be negative or positive, also they could be somewhere above 360. My goal is to calculate the distance, no matter if the rotation is negative or higher then 360°
EDIT
To make it clearer what I want: For example, I could could have the values -90deg and 270deg. This should result in a result of 0 for the distance. If the first element's rotation would change to either -100deg of -80deg, the distance should change to 10.
If you want this to work for any angle (including angles like 750 deg) and in a language where you have a remainder operator that's signed (like Java or JavaScript), then you need to do more work. If you're in a language with an unsigned operator, then the answer by Rory Daulton is good. (That is, in summary, use rot1%360 below where I call modulo(rot1,360) and similarly for rot2.)
First you need to make each negative angle into an equivalent positive angle. There's no single operator that will do this since, for example, -10 % 360 = -10 in these languages. You can get this with a function like this (assuming y is positive):
function modulo(x,y) {
var xPrime = x;
while(xPrime<0) {
xPrime += y; // ASSUMES y > 0
}
return xPrime % y;
}
Then you can do more or less as suggested by others, but using this custom function instead of the % operator.
var distance = Math.abs(modulo(rot1,360) - modulo(rot2,360))
distance = Math.min(distance, 360-distance)
Python code that seems to work in all cases is
dist = abs(x1 % 360 - x2 % 360)
dist = min(dist, 360 - dist)
That last line is needed to handle a case like x1=10; x2=350. The other answers would give 340 but the proper answer is 20.
Old topic but, the accepted answer is not really acceptable for a problem I had myself because of the while loop, and sadly that is the best I could find on a google search. However I found a better and faster solution if you might as well have to deal with very high negative rotation values.
This line of code takes a rotation value (r) and maps it to a range of 0-360.
r = (r<0) ? (r+(Math.ceil(-r/360)*360)) : (r%360);
Further explanation:
The accepted answer adds 360 every loop to the negative rotation value until it is positive, whereas my solution calculates how often it needs to add 360 and does that in one go.
So, I worked it out, following this answer:
function modulo(value, mod) {
return value - Math.floor( value/mod ) * value;
}
var dist = rotation1 - rotation2;
dist = Math.abs( modulo( (dist + 180), 360 ) - 180 );
EDIT
Actually, this answer works as well. Ported to JavaScript it would be:
var dist = Math.abs(rotation1 % 360 - rotation2 % 360);
dist = Math.min(dist, 360 - dist);
I like it, because it doesn't need the special modulo function.
I am creating three angles. These angles creates a triangle.I want to show calculated angle in my canvas, for that I am calculating angle and rounding off for showing.While calculating the angle's , I am rounding off the decimal digits using Math.round().
So if I got 65.25, 70.36, 44.39 degree as value of three angles and after rounding off it will be 65,70,44,which become 179 degree instead of 180 degree(One degree is missing here).How can I solve this problem ?
Here are some images for reference
One approach is to compute the third angle (rounded) based upon the other two, rather than simply rounding them all as you have done. For instance:
var th0 = 65.25;
var th1 = 70.36;
var th2 = 44.39;
var th0r = Math.round(th0);
var th1r = Math.round(th1);
var th2r = 180.0 - th0r - th1r;
This will force th0r + th1r + th2r to always sum to 180. You can become a little more sophisticated by picking the best angle to compute from the other two, but this will probably suffice for most applications.
To calculated the value of the derivative of a given function Func at a given point x, to get a good precision one would think this:
a = Fun( x - Number.MIN_VALUE)
b = Func( x + Number.MIN_VALUE)
return (b-a)/(2*Number.MIN_VALUE)
Now for any x + Number.MIN_VALUE (or x - Number.MIN_VALUE) both return x in javascript.
I tried of different values, and 1 + 1e-15 returns 1.000000000000001. Trying to get more precision, 1 + 1e-16 returns 1. So I'll have to use 1e-15 instead of Number.MIN_VALUE which is 5e-324.
Is there a way to get a better precision in this case in javascript?
This is not at all about javascript, actually.
Reducing the separation between the points will not increase your precision of the derivative. The values of the function in the close points will be computed with some error in the last digits, and finally, your error will be much larger than the point separation. Then you divide very small difference which has a huge relative error by a very small number, and you most likely get complete rubbish.
The best way to get a better value of the derivative is to calculate function in multiple points (with not very small separation) and then construct an approximation polynomial and differentiate it in the point of your interest.
I have used this code to exactly try to have the RGB code of color:
var huePixel = HueCanvas.css('background-color').match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);//["rgb(0, 70, 255", "0", "70", "255"]
var svPixel = SVCanvas.get(0).getContext("2d").getImageData(satPos,valPos,1,1).data;
//opacity*original + (1-opacity)*background = resulting pixel
var opacity =(svPixel[3]/255);
var r =parseInt((opacity*svPixel[0])+((1-opacity)*huePixel[1]));
var g =parseInt((opacity*svPixel[1])+((1-opacity)*huePixel[2]));
var b =parseInt((opacity*svPixel[2])+((1-opacity)*huePixel[3]));
The problem is that in some pixels , the RGB is not exactly the same . If i use Math.round than parseInt there is more problems , and more pixels have little changes than real ones.
I know that the problem is in var opacity =(svPixel[3]/255); , but i dont know how to put the equation to not have that problems.
Thanks for your attention.
I don't know the definite answer to your question (I'm not even sure I understand the question itself), but I'll take a shot.
It appears that you're trying to calculate the RGB value that you see when something else (the browser?) blends a non-opaque canvas on top of opaque background. (Are you sure this is the right thing to do at all?)
First, please don't use parseInt to round a number. It's used to parse strings and you should use it to convert huePixel[i] to an integer: parseInt(huePixel[i], 10) (note that I specify the radix explicitly to avoid numbers being parsed as octal).
To round values, you should use Math methods: Math.round (to closest integer), Math.ceil (round up) or Math.floor (round down).
Maybe the problem you're having is caused by rounding errors (hard to say without the specific inputs and expected outputs of the calculation). To minimize the rounding errors, you could try rewriting the formula like this:
(opacity * svPixel[0]) + ((1-opacity) * huePixel[1]) =
huePixel[1] + opacity * (svPixel[0]-huePixel[1]) =
huePixel[1] + svPixel[3] * (svPixel[0]-huePixel[1]) / 255