Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I have tried the following but it gives me nan
func sin (x: Double) -> Void {
var z = 1000
var n = 1.0
var w = 0.0
var b = (2*n-1)+1
var c = 0.0
while (b > 2){
c *= (b-1)
b -= 1
}
while (z > 0){
w += (power(x:(-1), y:(n-1))*(power(x:x, y:(2*n-1)))/c)
z -= 1
n += 1
}
print(w)
} where
power(x:base, y: exponent)
Example:
func sin(_ x: Double) -> Double {
func factorial(_ number: Int) -> Int {
var result = 1
for i in 2...number {
result *= i
}
return result
}
let x2 = x * x
let x4 = x2 * x2
let t1 = x * (1.0 - x2 / Double(factorial(3)))
let x5 = x4 * x
let t2 = x5 * (1.0 - x2 / (6 * 7)) / Double(factorial(5))
let x9 = x5 * x4
let t3 = x9 * (1.0 - x2 / (10 * 11)) / Double(factorial(9))
let x13 = x9 * x4
let t4 = x13 * (1.0 - x2 / (14 * 15)) / Double(factorial(13))
let result = t1 + t2 + t3 + t4
return round(1000 * result) / 1000
}
Usage:
let test = sin(90 * Double.pi / 180) // 90 degrees
print(test) // 1.0
The bug is obviously the c = 0, which you then multiply with more and more numbers... That's one of the situations where you can say "I don't know what that code does, but it's wrong".
sin x = x - x^3 / 3! + x^5 / 5! - x^7 / 7! etc.
A not completely inefficient approach is to start with the term x, and then figuring out how you get from one term to the next. You don't add up 1000 terms, that's ridiculous. You add up terms until adding the next term doesn't change the sum anymore.
And when you have this working, print sin (0.1), sin (0.2), say to sin (100.) and tell us if you find something unusual.
Related
I found something similar that gave me the general form of a line but after writing it out I came across some limitations with horizontal/vertical lines. Source here: https://math.stackexchange.com/questions/637922/how-can-i-find-coefficients-a-b-c-given-two-points
I'm not that good with math but I assume there are restrictions of the general equation of a line formula and attempting to calculate the distance with the distance formula using general coefficients of A,B,C did not work out.
Here's my original code that got the coefficients.
func computeEquationOfALineCoefficients(point1: CGPoint, point2: CGPoint) -> [CGFloat] {
// Computes the equation of a line in the form Ax + By + C = 0 thorugh
// y - y1 = (y2 - y1)/(x2 - x1) * (x - x1) or alternatively
// (y1-y2) * x + (x2-x1) * y + (x1-x2)*y1 + (y2-y1)*x1 = 0
// where a = y1 - y2, b = x2 - x1, c = (x1-x2)*y1 + (y2-y1)*x1
let x1: CGFloat = point1.x
let x2: CGFloat = point2.x
let y1: CGFloat = point1.y
let y2: CGFloat = point2.y
let A = y1 - y2
let B = x2 - x1
let C = (x1 - x2) * y1 + (y2 - y1) * x1
return [A, B, C]
}
and then the distance formula I was using
func computeDistanceBetweenPointAndLine(point: CGPoint, A: Float, B: Float, C: Float) -> Float {
let x: Float = Float(point.x)
let y: Float = Float(point.y)
let distance = abs(A * x + B * y + C) / (pow(A, 2) + pow(B, 2)).squareRoot()
return distance
}
it works fine until I introduce a horizontal line like the coordinates 0,0 and 150,0.
So I then decided to try the route with the perpendicular intersection between a point and a line but I'm stumped at solving for x by setting two equations equal to each other. I found a resource for that here: https://sciencing.com/how-to-find-the-distance-from-a-point-to-a-line-13712219.html but I am not sure how this is supposed to be represented in code.
Any tips or resources I may have yet to find are appreciated. Thank you!
i'm struggling with this geometry problem right now.
Let's say we have a line defined by point A(x1,y1) and point B(x2,y2)
We also have a point C(x3,y3).
What function written in SWIFT could give me the coordinates (X,Y) of the point that has the smallest distance from the line ? In other words, the point on the line which is the intersection between a perpendicular segment and the other point.
func getCoordsOfPointsWithSmallestDistanceBetweenLineAndPoint(lineX1: Double, lineY1: Double, lineX2: Double, lineY2: Double, pointX3: Double, pointY3: Double) -> [Double] {
// ???
return [x,y]
}
In a mathematical point of view you can :
first find the equation of the line :
y1 = a1x1+b1
a1 = (y2-y1) / (x2-x1)
b1 = y1-a1*x1
Then calculate the gradient of the second line knowing :
a1 * a2 = -1 <->
a2 = -1/a1
with a2 you can find the value of b for the second equation :
y3 = a2*x3 + b2 <->
b2 = y3 - a2*x3
Finally calculate the intersection of the 2 lines :
xi = (b2-b1) / (a1-a2)
y = a1*xi + b1
Then it's quite straightforward to bring that to swift :
typealias Line = (gradient:CGFloat, intercept:CGFloat)
func getLineEquation(point1:CGPoint, point2:CGPoint) -> Line {
guard point1.x != point2.x else {
if(point1.y != point2.y)
{
print("Vertical line : x = \(point1.x)")
}
return (gradient: .nan, intercept: .nan)
}
let gradient = (point2.y - point1.y)/(point2.x-point1.x)
let intercept = point1.y - gradient*point1.x
return (gradient: gradient, intercept: intercept)
}
func getPerpendicularGradient(gradient:CGFloat) -> CGFloat
{
guard gradient != 0 else {
print("horizontal line, the perpendicilar line is vertical")
return .nan
}
return -1/gradient
}
func getIntercept(forPoint point:CGPoint, withGradient gradient:CGFloat) -> CGFloat
{
return point.y - gradient * point.x
}
func getIntersectionPoint(line1:Line, line2:Line)-> CGPoint
{
guard line1.gradient != line2.gradient else {return CGPoint(x: CGFloat.nan, y: CGFloat.nan)}
let x = (line2.intercept - line1.intercept)/(line1.gradient-line2.gradient)
return CGPoint(x:x, y: line1.gradient*x + line1.intercept)
}
func getClosestIntersectionPoint(forLine line:Line, point:CGPoint) -> CGPoint
{
let line2Gradient = getPerpendicularGradient(gradient:line.gradient)
let line2 = (
gradient: line2Gradient,
intercept: getIntercept(forPoint: point, withGradient: line2Gradient))
return getIntersectionPoint(line1:line, line2:line2)
}
func getClosestIntersectionPoint(forLinePoint1 linePoint1:CGPoint, linePoint2:CGPoint, point:CGPoint) -> CGPoint
{
return getClosestIntersectionPoint(
forLine:getLineEquation(point1: linePoint1, point2: linePoint2),
point:point)
}
You can minimize the squared distance of C to a point on the straight line AB:
(CA + t.AB)² = t²AB² + 2t AB.CA + CA²
The minimum is achieved by
t = - AB.CA / AB²
and
CP = CA + t.AB
To elaborate on Yves Daoust answer which if converted to a function has the form
func closestPnt(x: Double, y: Double, x1: Double, y1: Double, px: Double, py: Double)->[Double]{
let vx = x1 - x // vector of line
let vy = y1 - y
let ax = px - x // vector from line start to point
let ay = py - y
let u = (ax * vx + ay * vy) / (vx * vx + vy * vy) // unit distance on line
if u >= 0 && u <= 1 { // is on line segment
return [x + vx * u, y + vy * u] // return closest point on line
}
if u < 0 {
return [x, y] // point is before start of line segment so return start point
}
return [x1, y1] // point is past end of line so return end
}
Note that the function is for line segments, if the closest points unit distance is behind the start or past the end then an end point is the closest.
If you want the point on a line (finitely long) then the following will do that.
func closestPnt(x: Double, y: Double, x1: Double, y1: Double, px: Double, py: Double)->[Double]{
let vx = x1 - x // vector of line
let vy = y1 - y
let ax = px - x // vector from line start to point
let ay = py - y
let u = (ax * vx + ay * vy) / (vx * vx + vy * vy) // unit distance on line
return [x + vx * u, y + vy * u] // return closest point on line
}
Note That both functions assume that !(x1 == x && y1 == y) is be true. IE the line segment MUST have a length > 0.
(x^3 - 2x^2 - 5) is my equation.First of all I have two values like x = 2 and x = 4. My first two values must be count for equation and them results must be negative and positive each time. And second step is (2 + 4) / 2 = 3 this time x = 3 in equation. And the math operation continue with last one positive value and one negative value. I try this
var x = 2.0
var equation = pow(x, 3) - 2 * pow(x, 2) - 5
switch x {
case x : 2
equation = pow(x, 3) - 2 * pow(x, 2) - 5
case x : 4
equation = pow(x, 3) - 2 * pow(x, 2) - 5
default:
0
}
print(equation)
How can I assign first two values like 2 and 4 for one var x ?
Apparently you want to implement the bisection method to find the (real) solution (“root”) of an equation. The first step is to define that equation as a function, so that it can be evaluated at various points:
func f(_ x: Double) -> Double {
return pow(x, 3) - 2 * pow(x, 2) - 5
}
Then you need two variables for the left and right boundary of the current interval. These must be chosen such that f(x) has opposite signs at the boundaries. In your example:
var xleft = 2.0 // f(xleft) < 0
var xright = 4.0 // f(xright) > 0
Now you can start the iteration: Compute f(x) at the midpoint of the current interval, and replace xleft of xright, depending on whether f(x) is negative or positive. Continue until the approximation is good enough for your purposes:
let eps = 0.0000001 // Desired precision
let leftSign = f(xleft).sign
repeat {
let x = (xleft + xright)/2.0
let y = f(x)
if y == 0 {
xleft = x
break
} else if y.sign == leftSign {
xleft = x
} else {
xright = x
}
// print(xleft, xright)
} while xright - xleft > eps
// Print approximate solution:
print(xleft)
The next step would be to implement the bisection method itself as a function:
func bisect(_ f: ((Double) -> Double), xleft: Double, xright: Double, eps: Double = 1.0e-6) -> Double {
let yleft = f(xleft)
let yright = f(xright)
precondition(yleft * yright <= 0, "f must have opposite sign at the boundaries")
var xleft = xleft
var xright = xright
repeat {
let x = (xleft + xright)/2.0
let y = f(x)
if y == 0 {
return x
} else if y.sign == yleft.sign {
xleft = x
} else {
xright = x
}
} while xright - xleft > eps
return (xleft + xright)/2.0
}
so that it can be used with arbitrary equations:
let sol1 = bisect({ x in pow(x, 3) - 2 * pow(x, 2) - 5 }, xleft: 2.0, xright: 4.0)
print(sol1) // 2.690647602081299
let sol2 = bisect({ x in cos(x/2)}, xleft: 3.0, xright: 4.0, eps: 1.0e-15)
print(sol2) // 3.1415926535897936
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
Here is my issue as an example:
I have two variables, minNumber = 12 & maxNumber = 24 and a maxLimit = 30
and I have a percentage between 1.0 - 0.0, I want the following result:
when the percentage decrease from 1.0 to 0.5, I want minNumber to increase to the maxLimit, and when the percentage decrease from 0.5 to 0.0, the maxLimit went down to maxNumber
so,
percentage = 1.0
var result = 0
while percentage >= 0 {
if percentage < 0.5 {
result = 12.1, 12.2, ..., 29.8, 29.9, 30 (what formula can produce this sequence)
} else {
result = 30, 29.9, ..., 24.1, 24.0 (what formula can produce this sequence)
}
percentage = percentage - 0.1
print("\(result)")
}
If I understand your question correctly, you want result value to "move" in an angle-like shape from minNumber via maxLimit to maxNumber. The basis behind this transformation is following formula. If you have a value X from a range Xmin to XMax and you want to map it to a range Ymin to Ymax then
Y = (Ymin * (Xmax - X) + Ymax * (X - Xmin)) / (Xmax - Xmin)
For you case you should apply this formula for two intervals:
mapping [0; 0.5] range to [minNumber; maxLimit]
mapping [0.5; 1.0] range to [maxLimit; maxNumber]
I think the code becomes more clear if you call:
leftNumber = minNumber
middleNumber = maxLimit
rightNumber = maxNumber
and use two while loops instead of one with inner if:
let leftNumber = 12.0 // minNumber
let middleNumber = 30.0 // maxLimit
let rightNumber = 23.0 // maxNumber
let leftPercentage = 0.0
let middlePercentage = 0.5
let rightPercentage = 1.0
let percentageStep = 0.1
var percentage = leftPercentage
var result = 0.0
while percentage <= middlePercentage {
result = ((percentage - leftPercentage) * middleNumber + (middlePercentage - percentage) * leftNumber)/(middlePercentage - leftPercentage)
percentage = percentage + percentageStep
print("\(result)")
}
while percentage <= rightPercentage {
result = ((rightPercentage - percentage) * middleNumber + (percentage - middlePercentage) * rightNumber)/(rightPercentage - middlePercentage)
percentage = percentage + percentageStep
print("\(result)")
}
You can see output of this code here
Update: Where the formula comes from?
When we say that "you have a value X from a range Xmin to XMax and you want to map it to a range Ymin to Ymax", what exactly do you mean by "map"? Usually what you want is that X splits the [Xmin, Xmax] range in the same proportion as Y splits the [Ymin, Ymax] range. Let's write that:
(X - Xmin)/(Xmax - Xmin) = (Y - Ymin)/(Ymax - Ymin)
If you try to solve it for Y you can see that:
(Y - Ymin) = (X - Xmin)/(Xmax - Xmin)*(Ymax - Ymin) =
= (Ymax * (X - Xmin) - Ymin * (X-Xmin))/(Xmax - Xmin)
so
Y = (Ymax * (X - Xmin) - Ymin * (X - Xmin))/(Xmax - Xmin) + Ymin =
= (Ymax * (X - Xmin) + Ymin * (Xmin - X) + Ymin * (Xmax - Xmin))/(Xmax - Xmin) =
= (Ymax * (X - Xmin) + Ymin * (Xmax - X))/(Xmax - Xmin)
which is exactly that formula.
I try to find value of polynomial from pr. Here is my code:
let x = Double(pr)
let x2 : Double = pow(x, 2.0)
let x3 : Double = pow(x, 3.0)
let x4 : Double = pow(x, 4.0)
let r = CGFloat( 4.8 * x4 - 10.4 * x3 + 5.7 * x2 + 1.05 * x + 0.95 )
let g = CGFloat( 4.8 * x4 - 8.8 * x3 + 3.3 * x2 + 1.65 * x + 0.0 )
let b = CGFloat(0.0)
let color = UIColor(red: r, green: g, blue: b, alpha: 1.0)
return color.CGColor
There is not so much to explain, it just throws complier’s error: “Could not find overload for ‘-‘ that accepts supplied arguments. Also I tried to use powf(x, 2) with float types everywhere. pr is function CGFloat type parameter. Here is screenshot: .
Thanks!
This seems to be a compiler bug (and it might be worth a bug report at Apple).
The compiler messages in the Report navigator show
note: expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions
let g = CGFloat( 4.8 * x4 - 8.8 * x3 + 3.3 * x2 + 1.65 * x + 0.0 )
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As a workaround, you can assign the expression to a temporary variable first:
let tmp = 4.8 * x4 - 10.4 * x3 + 5.7 * x2 + 1.05 * x + 0.95
let r = CGFloat( tmp )
Remark: A more efficient method to evaluate a polynomial at a given point
is Horner's method:
let tmp = (((4.8 * x - 10.4) * x + 5.7) * x + 1.05) * x + 0.95
where you don't have to compute the various powers of x.