This often returns NAN ("Not A Number") depending on input:
#define PI 3.1415f
GLfloat sineEaseIn(GLfloat ratio) {
return 1.0f-cosf(ratio * (PI / 2.0f));
}
I tried making PI a few digits smaller to see if that would help. No dice.
Then I thought it might be a datatype mismatch, but float and glfloat seem to be equivalent:
gl.h
typedef float GLfloat;
math.h
extern float cosf( float );
Is this a casting issue?
I suspect that one of the following is afoot:
your input value to ratio may not be what you expect it to be, and ratio itself is possibly NaN
the cosf that you're calling isn't the one in math.h
Otherwise, there doesn't appear to be anything wrong with your expression.
Related
I've been writing a CAD type program for fun in JAVA. The other day I wrote some code to define a line which was tangent to 2 circles. I've been checking my numbers with a commercial CAD program and they have been fairly close. Usually to the 9th decimal point. My results really only need to be stored in an array to 7 decimal points. After successfully defining the line tangent to the 2 circles, I decided to test it and define a point which was the intersection of the line and one of the circles.
In one case I got the result I was looking for, in another case I got no intersection. After looking at a few of the calculations I realized I was getting a very very small variation of maybe 9 or ten decimal places. I'm thinking of rewriting the code using BigDecimal.
This is a small snippet of some of the code I need to rewrite. Once I started it became much more cumbersome than I was wanting to do. I'm thinking about just converting the results using BigDecimal and using the original code unless there is an easy way to convert the following code to a BigDecimal type of format.
private float[] offsetLine(float lnx1, float lny1, float lnz1, float lnx2, float lny2, float lnz2, String direction, float offset) {
double deltax = Math.abs(lnx2 - lnx1);
double deltay = Math.abs(lny2 - lny1);
double lineLength = Math.sqrt(deltax * deltax + deltay * deltay);
double stepx = (offset * deltay) / lineLength;
double stepy = (offset * deltax) / lineLength;
Ok I'll answer my own question. Here's some code I dug up. I could only round to 6 decimal places to get the rounding I wanted. Once I did my calculations in double values I called the subroutine roundDbl
double checkRadius1 = Math.sqrt(((cir1x - offsetpts[0])*(cir1x - offsetpts[0])) + ((cir1y - offsetpts[1]) * (cir1y - offsetpts[1])));
double checkRadiusRounded = roundDbl(checkRadius1, 6); //round to 6 decimal places
public static Float roundDbl(Double dblValue, int decimalPlace) {
String tempDblString = Double.toString(dblValue);
String tempDbl = new BigDecimal(tempDblString).setScale(decimalPlace, RoundingMode.HALF_UP).stripTrailingZeros().toPlainString();
return Float.valueOf(tempDbl);
}
I need to rotate a direction vector towards another with a maximum angle in a compute shader, just like the Vector3.RotateTowards(from, to, maxAngle, 0) function does. This needs to happen inside the compute shader, since I cannot send the needed values from and to the GPU for performance reasons. Any suggestions on how to implement this?
This is adapted from a combination of this post on the Unity forums by vc1001 and this shadertoy entry by demofox. I haven't tested this and it has been a while since I've done HLSL/cg coding, sop lease let me know if there are bugs--especially syntax errors.
float3 slerp(float3 current, float3 target, float maxAngle)
{
// Dot product - the cosine of the angle between 2 vectors.
float dot = dot(current, target);
// Clamp it to be in the range of Acos()
// This may be unnecessary, but floating point
// precision can be a fickle mistress.
dot = clamp(dot, -1, 1);
// Acos(dot) returns the angle between start and end,
// And multiplying that by percent returns the angle between
// start and the final result.
float delta = acos(dot);
float theta = min(1.0f, maxAngle / delta);
float3 relativeVec = normalize(target - current*dot); // Orthonormal basis
float3 slerped = ((start*cos(theta)) + (relativeVec*sin(theta)));
}
I'd like to do this:
layout(location = 0) in dvec2 c;
But apparently I can't:
$ glslc mandlebrot.frag
mandlebrot.frag:7: error: 'double' : must be qualified as flat in
However, I require this input be interpolated, not flat. Is there a way to do this?
Nope:
Fragment shader inputs that are, or contain, integral or double-precision floating-point types must be qualified with the interpolation qualifier flat.
So you're going to have to make them floats.
While Nicol's answer appears to be technically correct, there is a work-around. A float value has more than enough precision to target a pixel on a screen; it just may not have enough to target a position within the "world" (in this case, a fractal).
The solution then is to use a uniform buffer to pass world coordinates for some fixed point relative to the screen (in this case, the centre), then compute pixel coordinates from that:
layout(set = 0, binding = 1) uniform Locals {
dvec2 centre;
dvec2 scale;
};
void main() {
dvec2 c = centre + dvec2(cf) * scale;
...
}
we, developers very often need to calculate angle to perform rotation. Usually we can use atan2() function but sometimes we need more precision. What do you do then?
I know that theoretically atan2 is precise but in my system (iOS) it's inaccurate about 0.05 radians so it's big difference. That's not just my problem. I've seen similar opinions.
atan2 is used to get an angle a from a vector (x,y). If then you use this angle to apply a rotation you will use cos(a) and sin(a). You could simply compute cos and sin by normalizing (x,y), and keep them instead of the angle. Precision will be higher, and you will save a lot of cycles lost in trigonometric functions.
Edit. If you really want an angle from (x,y), it can be computed using variants of CORDIC to the precision you need.
you can use atan2l if long double has more precision than double in your system.
long double atan2l(long double y, long double x);
On iOS, I've found that the standard trigonometry operators are precise to roughly 13 or 14 decimal digits, so it sounds very odd that you're seeing errors on the order of 0.05 radians. If you can produce code and specific values that demonstrate this, please file a bug report on the behavior (and post the code here so that we can have a record of it).
That said, if you really need high precision for your trigonometry operators, I've modified a few of the routines that Dave DeLong created for his DDMathParser code. These routines use NSDecimal for performing the math, giving you up to ~34 digits of decimal precision while avoiding your standard floating point problems with representing base 10 decimals. You can download the code for these modified routines from here.
An NSDecimal version of atan() is calculated using the following code:
NSDecimal DDDecimalAtan(NSDecimal x) {
// from: http://en.wikipedia.org/wiki/Inverse_trigonometric_functions#Infinite_series
// The normal infinite series diverges if x > 1
NSDecimal one = DDDecimalOne();
NSDecimal absX = DDDecimalAbsoluteValue(x);
NSDecimal z = x;
if (NSDecimalCompare(&one, &absX) == NSOrderedAscending)
{
// y = x / (1 + sqrt(1+x^2))
// Atan(x) = 2*Atan(y)
// From: http://www.mathkb.com/Uwe/Forum.aspx/math/14680/faster-Taylor-s-series-of-Atan-x
NSDecimal interiorOfRoot;
NSDecimalMultiply(&interiorOfRoot, &x, &x, NSRoundBankers);
NSDecimalAdd(&interiorOfRoot, &one, &interiorOfRoot, NSRoundBankers);
NSDecimal denominator = DDDecimalSqrt(interiorOfRoot);
NSDecimalAdd(&denominator, &one, &denominator, NSRoundBankers);
NSDecimal y;
NSDecimalDivide(&y, &x, &denominator, NSRoundBankers);
NSDecimalMultiply(&interiorOfRoot, &y, &y, NSRoundBankers);
NSDecimalAdd(&interiorOfRoot, &one, &interiorOfRoot, NSRoundBankers);
denominator = DDDecimalSqrt(interiorOfRoot);
NSDecimalAdd(&denominator, &one, &denominator, NSRoundBankers);
NSDecimal y2;
NSDecimalDivide(&y2, &y, &denominator, NSRoundBankers);
// NSDecimal two = DDDecimalTwo();
NSDecimal four = DDDecimalFromInteger(4);
NSDecimal firstArctangent = DDDecimalAtan(y2);
NSDecimalMultiply(&z, &four, &firstArctangent, NSRoundBankers);
}
else
{
BOOL shouldSubtract = YES;
for (NSInteger n = 3; n < 150; n += 2) {
NSDecimal numerator;
if (NSDecimalPower(&numerator, &x, n, NSRoundBankers) == NSCalculationUnderflow)
{
numerator = DDDecimalZero();
n = 150;
}
NSDecimal denominator = DDDecimalFromInteger(n);
NSDecimal term;
if (NSDecimalDivide(&term, &numerator, &denominator, NSRoundBankers) == NSCalculationUnderflow)
{
term = DDDecimalZero();
n = 150;
}
if (shouldSubtract) {
NSDecimalSubtract(&z, &z, &term, NSRoundBankers);
} else {
NSDecimalAdd(&z, &z, &term, NSRoundBankers);
}
shouldSubtract = !shouldSubtract;
}
}
return z;
}
This uses a Taylor series approximation, with some shortcuts to speed convergence. I believe that the precision might not be the full 34 digits at results very close to Pi / 4 radians, so I might still need to fix that.
If you need extreme precision this is an option, but again what you're reporting shouldn't be happening with double values, so there's something odd here.
Use angles very often? No, you don't. Out of 10 times that I have seen a developer use angles, 7 times he should have used linear algebra instead and avoid any trigoniometric functions.
A rotation is better done with a matrix, not with an angle. See also this question:
CGAffineTranformRotate atan2 inaccuration
I keep getting error in my iPhone programing when I try to use pi. I'm trying
float pNumber = 100*cos(2 * pi * (days/23));
But i get errors that say:
_pi, referenced from
_pi$non_lazy_ptr
I saw somewhere on the internet to use M_PI and it compiles but I don't think it gives me the correct calculation.
When I try:
float pNumber = 100*cos(2 * M_PI * (15746/23));
I get 0
Thanks
The integer division probably needs to be coerced into a floating point one (cast one of the numbers to a double - or use the notation 23.0 to indicate that you want a floating point division).
Try printing out M_PI and see what it says (printf("M_PI = %16.9g\n", M_PI); in C).
Did you include the declaration for cos()? If not, it may be interpreted as a function returning an integer (#include <math.h> perhaps).
Example code (tested in C on Solaris 10 SPARC with GCC 4.3.3):
#include <math.h>
#include <stdio.h>
int main(void)
{
float pNumber = 100*cos(2 * M_PI * (15746/23));
printf("M_PI = %16.9g\n", M_PI);
printf("pNum = %16.9g\n", pNumber);
pNumber = 100*cos(2 * M_PI * (15746/23.0));
printf("pNum = %16.9g\n", pNumber);
return 0;
}
Example output:
M_PI = 3.14159265
pNum = 100
pNum = -77.5711288
C/C++ and hence Objective C/C++ does not promote integers to floats when doing normal division.
So in C/C++ the expression 15746/23 evaluates to 567, not to 567.71207 as you might naively expect.
C will promote integers to floats as necessary if one or other operand is a float, so all you need to do is use 15746.0 or 23.0 in your expression, ie change to
float pNumber = 100*cos(2 * M_PI * (15746/23.0));
The 100 will automatically be promoted because cos returns a float (actually a double, but I will ignorefloat/double percissions issues). The 2 is promoted to a float because M_PI is a float. And the 15746 is promoted to a float because 23.0 is a float.
However, it would not hurt to add the .0 to all the constants, ie:
float pNumber = 100.0*cos(2.0 * M_PI * (15746.0/23.0));
The problem is the integer division in the innermost part of the expression, which truncates the value (omitting the fractional part). One option, as mentioned, is to make every constant a floating point number, either by adding ".0" or "f" after it. Alternatively, you can omit the parentheses from the innermost expression entirely. Since M_PI is a floating point number, and multiplication in C is left-associative (meaning it proceeds from left to right) the first multiplication (2 * M_PI) will be promoted to a float, as will each successive multiply. Since cos() returns a float, pNumber will be assigned a float without having performed any integer division, hence no loss of precision. (Note: It's not usually wise to count on operator associativity or precedence, but in this case I'm just trying to demonstrate that it would in fact work.)
As far as the range of numbers you should expect to see, recall that the cosine (unmodified) ranges from -1 to +1, not 0 to 1, so you would actually see -100 to 100 (in theory). To get the correct range, you'd want to add 1, then multiply by 50.
Incidentally, the compile errors you get in the first case are because pi is not defined. The guidance to use M_PI is correct — for math constants, it's always smarter (and more consistent) to use what the system provides. If you're curious, on Leopard these constants are #defined in Math.h, lines 528-540. You can open the file by using File > Open Quickly... (Cmd-Shift-D) and typing "Math.h", or by double-clicking on M_PI in your code while holding down Command.
Why use a sinusoid in the first place ?
If the goal is to have a fonction ranging from 0 to 100 then 100 to 0 in 23 days, you could use:
// x ranges from 0 to 2
float x = (days % 23)/11.5;
// pNumber is a saw ranging from 0 to 100
float pNumber = 100 * abs(x - 1);
You can also replace the x by a cosine if you really want one, as 2*pi/23 ~= 0.273, you have
float x = 1 + cos((days % 23)*0.273);