How can I round Int to nearest 10 in Swift? - swift

I have a small problem in rounded numbers to the nearest 10
var finalResult = Int(textfield.text!)
let x = Double(finalResult)
let y = x.rounded() / 5
print(x) // 18.0
print(y) // 3.6
i want result to be like this
// if x = 6.0 ... 14.0
// y = 2
// if x = 15.0
// y = 3
// if x = 16.0 ... 24.0
// y = 4
// if x = 25.0
// y = 5
// if x = 26.0 ... 34.0
// y = 6
I hope I have asked a question that benefits me and others
I hope that I have explained the question well

You need to use round function and x % 5 == 0 check.
let values = (6...100).map({ Double($0) })
func round(_ value: Double, toNearest: Double) -> Double {
return round(value / toNearest) * toNearest
}
for x in values {
if x.truncatingRemainder(dividingBy: 5) == 0 {
print("x - \(x), y - \(Int(x / 5))")
} else {
let rounded = round(x, toNearest: 10.0)
print("x - \(x), y - \(Int(rounded / 5))")
}
}

Related

Splitting method algorithm

(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

Procedural mesh not rendering lighting [SceneKit - Xcode]

I am quite new to swift and Xcode however, I have been programming in other languages for several years. I am trying to procedurally create a 3D mesh in SceneKit (iOS). My code works as expected however, when running the application the generated object renders a flat black colour, ignoring all lighting. I have also added a cube to the scene to show that the scene lighting is working.
I would imagine that there is either a problem with the shader or that I need to define the normals of the geometry to fix this. I have tried playing around with a few properties of the SCNMaterial, but they don't seem to change anything.
If it is just a case of defining the normals, please could you advise how I would do this in Swift / SceneKit. Or perhaps I have missed something else, any help would be much appreciated.
Screenshot below:
My code below:
public static func CreateMesh (size: CGFloat, resolution: CGFloat) -> SCNNode? {
let axisCount = Int(floor(size / resolution))
let bottomLeft = CGVector(
dx: CGFloat(-(axisCount / 2)) * resolution,
dy: CGFloat(-(axisCount / 2)) * resolution
)
var verts = Array(
repeating: Array(
repeating: (i: Int(0), pos: SCNVector3.init(x: 0, y: 0, z: 0)),
count: axisCount),
count: axisCount
)
var vertsStream = [SCNVector3]()
var i : Int = 0
for x in 0...axisCount-1 {
for y in 0...axisCount-1 {
verts[x][y] = (
i,
SCNVector3(
x: Float(bottomLeft.dx + CGFloat(x) * resolution),
y: Float.random(in: 0..<0.1),
z: Float(bottomLeft.dy + CGFloat(y) * resolution)
)
)
vertsStream.append(verts[x][y].pos)
i += 1
}
}
var tris = [(a: Int, b: Int, c: Int)]()
var trisStream = [UInt16]()
for x in 0...axisCount - 2 {
for y in 0...axisCount - 2 {
// Quad
tris.append((
a: verts[x][y].i,
b: verts[x][y+1].i,
c: verts[x+1][y+1].i
))
tris.append((
a: verts[x+1][y+1].i,
b: verts[x+1][y].i,
c: verts[x][y].i
))
}
}
for t in tris {
trisStream.append(UInt16(t.a))
trisStream.append(UInt16(t.b))
trisStream.append(UInt16(t.c))
}
// Create scene element
let geometrySource = SCNGeometrySource(vertices: vertsStream)
let geometryElement = SCNGeometryElement(indices: trisStream, primitiveType: .triangles)
let geometryFinal = SCNGeometry(sources: [geometrySource], elements: [geometryElement])
let node = SCNNode(geometry: geometryFinal)
////////////////////////
// FIX MATERIAL
////////////////////////
let mat = SCNMaterial()
mat.diffuse.intensity = 1
mat.lightingModel = .blinn
mat.blendMode = .replace
node.geometry?.materials = [mat]
return node
}
After a lot of searching I managed to find a post with a line of code that looks something like this:
let gsNormals = SCNGeometrySource(normals: normalStream)
So from there I managed to work out how to set the surface normals. It seems like there really isn't a lot of online content / learning material when it comes to the more advanced topics like this in Xcode / Swift, which is quite unfortunate.
I have set it up to create a parabolic shape plane, just for testing. But this code will be used to generate a mesh from a height map, which should now be easy to implement. I think it's pretty useful code, so I have included it below incase anyone else ever has the same issue that I did.
public static func CreateMesh (size: CGFloat, resolution: CGFloat) -> SCNNode? {
let axisCount = Int(floor(size / resolution))
let bottomLeft = CGVector(
dx: CGFloat(-(axisCount / 2)) * resolution,
dy: CGFloat(-(axisCount / 2)) * resolution
)
/// Verticies ///
var verts = Array(
repeating: Array(
repeating: (i: Int(0), pos: SCNVector3.init(x: 0, y: 0, z: 0)),
count: axisCount),
count: axisCount
)
var vertsStream = [SCNVector3]()
var i = 0
for x in 0...axisCount - 1 {
for y in 0...axisCount - 1 {
var dx = axisCount / 2 - x
dx = dx * dx
var dy = axisCount / 2 - y
dy = dy * dy
let yVal = Float(Double(dx + dy) * 0.0125)
verts[x][y] = (
i: i,
pos: SCNVector3(
x: Float(bottomLeft.dx + CGFloat(x) * resolution),
//y: Float.random(in: 0..<0.1),
y: yVal,
z: Float(bottomLeft.dy + CGFloat(y) * resolution)
)
)
vertsStream.append(verts[x][y].pos)
i += 1
}
}
///
/// Triangles ///
var tris = [(a: Int, b: Int, c: Int)]()
var trisStream = [UInt32]()
for x in 0...axisCount - 2 {
for y in 0...axisCount - 2 {
// Quad
tris.append((
a: verts[x][y].i,
b: verts[x][y+1].i,
c: verts[x+1][y].i
))
tris.append((
a: verts[x+1][y].i,
b: verts[x][y+1].i,
c: verts[x+1][y+1].i
))
}
}
for t in tris {
trisStream.append(UInt32(t.a))
trisStream.append(UInt32(t.b))
trisStream.append(UInt32(t.c))
}
///
/// Normals ///
var normalStream = [SCNVector3]()
for x in 0...axisCount - 1 {
for y in 0...axisCount - 1 {
// calculate normal vector perp to average plane
let leftX = x == 0 ? 0 : x - 1
let rightX = x == axisCount - 1 ? axisCount - 1 : x + 1
let leftY = y == 0 ? 0 : y - 1
let rightY = y == axisCount - 1 ? axisCount - 1 : y + 1
let avgXVector = float3(verts[rightX][y].pos) - float3(verts[leftX][y].pos)
let avgYVector = float3(verts[x][rightY].pos) - float3(verts[x][leftY].pos)
// If you are unfamiliar with how to calculate normals
// search for vector cross product, this is used to find
// a vector that is orthogonal to two other vectors, in our
// case perpendicular to the surface
let normal = cross(
normalize(avgYVector),
normalize(avgXVector)
)
normalStream.append(SCNVector3(normal))
}
}
///
// Create scene element
let gsGeometry = SCNGeometrySource(vertices: vertsStream)
let gsNormals = SCNGeometrySource(normals: normalStream)
let geometryElement = SCNGeometryElement(indices: trisStream, primitiveType: .triangles)
let geometryFinal = SCNGeometry(sources: [gsGeometry, gsNormals], elements: [geometryElement])
let node = SCNNode(geometry: geometryFinal)
let mat = SCNMaterial()
mat.isDoubleSided = true
mat.lightingModel = .blinn
node.geometry?.materials = [mat]
return node
}

Swift CORDIC Algorithm gives constant answer

I tried to translate the MATLAB language on Cordic wikipedia webpage
However when I type those:
print(cordic(beta: Double.pi/9, n: 20))
print(cordic(beta: Double.pi/8, n: 20))
I get
[-0.17163433840184755, 0.98516072489744066]
[-0.17163433840184755, 0.98516072489744066]
It's always giving me a constant answer. Why? I'm sure that the "angle" and "Kvalues" arrays are properly calculated.
Here's the code:
import Foundation
var angles: [Double] = []
for i: Double in stride(from: 0, to: 27, by: 1) {
angles.append(atan(pow(2, -i)))
}
var Kvalues: [Double] = []
for i: Double in stride(from: 0, to: 23, by: 1) {
Kvalues.append(1/sqrt(abs(Double(1) + pow(2,-2 * i))))
if i > 0 {
Kvalues[Kvalues.count - 1] *= Kvalues[Kvalues.count - 2]
}
}
func min(_ a: Int, _ b: Int) -> Int {
return a > b ? b : a
}
func cordic(beta: Double, n: Int) -> [Double] {
var beta1 = beta
let Kn = Kvalues[min(n, Kvalues.count - 1)]
var v: [Double] = [1,0]
var poweroftwo: Double = 1
var angle = angles[0]
for j in 0 ..< n {
let sigma: Double = beta < 0 ? -1 : 1
let factor: Double = sigma * poweroftwo
v = [v[0] - v[1] * factor, v[1] + v[0] * factor]
beta1 -= sigma * angle
poweroftwo /= 2
angle = j + 2 > angles.count ? angle / 2 : angles[j + 2]
}
return [v[0] * Kn, v[1] * Kn]
}
print(cordic(beta: Double.pi/9, n: 20))
print(cordic(beta: Double.pi/8, n: 20))
You get the same result for different input because in
let sigma: Double = beta < 0 ? -1 : 1
beta should be beta1, which is the local variable that is
updated in the loop.
But even after fixing that the results are not correct, and that is
caused by two "off-by-one" index errors. The arrays in the algorithm
description are 1-based and Swift arrays are 0-based. So
let Kn = Kvalues[min(n, Kvalues.count - 1)]
// should be
let Kn = Kvalues[min(n-1, Kvalues.count - 1)]
and
angle = j + 2 > angles.count ? angle / 2 : angles[j + 2]
// should be
angle = j + 1 >= angles.count ? angle / 2 : angles[j + 1]
The angles and Kvalues arrays should be defined for i from 0 up to and including 27 resp. 23.
Finally, there is no need to define your own min function as there is one in the Swift standard library.
Putting it all together your code would be:
var angles: [Double] = []
for i: Double in stride(from: 0, through: 27, by: 1) {
angles.append(atan(pow(2, -i)))
}
var Kvalues: [Double] = []
for i: Double in stride(from: 0, through: 23, by: 1) {
Kvalues.append(1/sqrt(abs(Double(1) + pow(2,-2 * i))))
if i > 0 {
Kvalues[Kvalues.count - 1] *= Kvalues[Kvalues.count - 2]
}
}
func cordic(beta: Double, n: Int) -> [Double] {
var beta1 = beta
let Kn = Kvalues[min(n-1, Kvalues.count - 1)]
var v: [Double] = [1,0]
var poweroftwo: Double = 1
var angle = angles[0]
for j in 0 ..< n {
let sigma: Double = beta1 < 0 ? -1 : 1
let factor: Double = sigma * poweroftwo
v = [v[0] - v[1] * factor, v[1] + v[0] * factor]
beta1 -= sigma * angle
poweroftwo /= 2
angle = j + 1 >= angles.count ? angle / 2 : angles[j + 1]
}
return [v[0] * Kn, v[1] * Kn]
}
And that produces good approximations:
print(cordic(beta: Double.pi/9, n: 20)) // [0.93969210812600046, 0.34202155184390554]
print(cordic(beta: Double.pi/8, n: 20)) // [0.92388022188807306, 0.38268176805806309]
The exact values are
print(cos(Double.pi/9), sin(Double.pi/9)) // 0.939692620785908 0.342020143325669
print(cos(Double.pi/8), sin(Double.pi/8)) // 0.923879532511287 0.38268343236509

Swift Inverse FFT (IFFT) Via Chirp Z-Transform (CZT)

For arbitrary sample sizes (samples not equal to 2^N), I have been able to implement the FFT via the chirp Z-transform (CZT) using iOS Accelerate's FFT function (that only works for samples equal to 2^N).
The results are good and match the Matlab FFT output for any arbitrary length sequence (signal). I paste the code below.
My next challenge is to use iOS Accelerate's FFT function (that only works for samples equal to 2^N) for accomplishing an inverse FFT on arbitrary sample sizes (samples not equal to 2^N).
Since my CZT accomplishes arbitrary length FFT now (see below), I am hoping that an inverse CZT (ICZT) would accomplish an arbitrary length IFFT using iOS Accelerate's FFT function (that only works for samples equal to 2^N).
Any suggestions/guidence?
// FFT IOS ACCELERATE FRAMEWORK (works only for 2^N samples)
import Accelerate
public func fft(x: [Double], y: [Double], type: String) -> ([Double], [Double]) {
var real = [Double](x)
var imaginary = [Double](y)
var splitComplex = DSPDoubleSplitComplex(realp: &real, imagp: &imaginary)
let length = vDSP_Length(floor(log2(Float(real.count))))
let radix = FFTRadix(kFFTRadix2)
let weights = vDSP_create_fftsetupD(length, radix)
switch type.lowercased() {
case ("fft"): // CASE FFT
vDSP_fft_zipD(weights!, &splitComplex, 1, length, FFTDirection(FFT_FORWARD))
vDSP_destroy_fftsetup(weights)
case ("ifft"): // CASE INVERSE FFT
vDSP_fft_zipD(weights!, &splitComplex, 1, length, FFTDirection(FFT_INVERSE))
vDSP_destroy_fftsetup(weights)
real = real.map({ $0 / Double(x.count) }) // Normalize IFFT by sample count
imaginary = imaginary.map({ $0 / Double(x.count) }) // Normalize IFFT by sample count
default: // DEFAULT CASE (FFT)
vDSP_fft_zipD(weights!, &splitComplex, 1, length, FFTDirection(FFT_FORWARD))
vDSP_destroy_fftsetup(weights)
}
return (real, imaginary)
}
// END FFT IOS ACCELERATE FRAMEWORK (works only for 2^N samples)
// DEFINE COMPLEX NUMBERS
struct Complex<T: FloatingPoint> {
let real: T
let imaginary: T
static func +(lhs: Complex<T>, rhs: Complex<T>) -> Complex<T> {
return Complex(real: lhs.real + rhs.real, imaginary: lhs.imaginary + rhs.imaginary)
}
static func -(lhs: Complex<T>, rhs: Complex<T>) -> Complex<T> {
return Complex(real: lhs.real - rhs.real, imaginary: lhs.imaginary - rhs.imaginary)
}
static func *(lhs: Complex<T>, rhs: Complex<T>) -> Complex<T> {
return Complex(real: lhs.real * rhs.real - lhs.imaginary * rhs.imaginary,
imaginary: lhs.imaginary * rhs.real + lhs.real * rhs.imaginary)
}
}
extension Complex: CustomStringConvertible {
var description: String {
switch (real, imaginary) {
case (_, 0):
return "\(real)"
case (0, _):
return "\(imaginary)i"
case (_, let b) where b < 0:
return "\(real) - \(abs(imaginary))i"
default:
return "\(real) + \(imaginary)i"
}
}
}
// DEFINE COMPLEX NUMBERS
// DFT BASED ON CHIRP Z TRANSFORM (CZT)
public func dft(x: [Double]) -> ([Double], [Double]) {
let m = x.count // number of samples
var N: [Double] = Array(stride(from: Double(0), through: Double(m - 1), by: 1.0))
N = N.map({ $0 + Double(m) })
var NM: [Double] = Array(stride(from: Double(-(m - 1)), through: Double(m - 1), by: 1.0))
NM = NM.map({ $0 + Double(m) })
var M: [Double] = Array(stride(from: Double(0), through: Double(m - 1), by: 1.0))
M = M.map({ $0 + Double(m) })
let nfft = Int(pow(2, ceil(log2(Double(m + m - 1))))) // fft pad
var p1: [Double] = Array(stride(from: Double(-(m - 1)), through: Double(m - 1), by: 1.0))
p1 = (zip(p1, p1).map(*)).map({ $0 / Double(2) }) // W = WR + j*WI has to be raised to power p1
var WR = [Double]()
var WI = [Double]()
for i in 0 ..< p1.count { // Use De Moivre's formula to raise to power p1
WR.append(cos(p1[i] * 2.0 * M_PI / Double(m)))
WI.append(sin(-p1[i] * 2.0 * M_PI / Double(m)))
}
var aaR = [Double]()
var aaI = [Double]()
for j in 0 ..< N.count {
aaR.append(WR[Int(N[j] - 1)] * x[j])
aaI.append(WI[Int(N[j] - 1)] * x[j])
}
let la = nfft - aaR.count
let pad: [Double] = Array(repeating: 0, count: la) // 1st zero padding
aaR += pad
aaI += pad
let (fgr, fgi) = fft(x: aaR, y: aaI, type: "fft") // 1st FFT
var bbR = [Double]()
var bbI = [Double]()
for k in 0 ..< NM.count {
bbR.append((WR[Int(NM[k] - 1)]) / (((WR[Int(NM[k] - 1)])) * ((WR[Int(NM[k] - 1)])) + ((WI[Int(NM[k] - 1)])) * ((WI[Int(NM[k] - 1)])))) // take reciprocal
bbI.append(-(WI[Int(NM[k] - 1)]) / (((WR[Int(NM[k] - 1)])) * ((WR[Int(NM[k] - 1)])) + ((WI[Int(NM[k] - 1)])) * ((WI[Int(NM[k] - 1)])))) // take reciprocal
}
let lb = nfft - bbR.count
let pad2: [Double] = Array(repeating: 0, count: lb) // 2nd zero padding
bbR += pad2
bbI += pad2
let (fwr, fwi) = fft(x: bbR, y: bbI, type: "fft") // 2nd FFT
let fg = zip(fgr, fgi).map { Complex<Double>(real: $0, imaginary: $1) } // complexN 1
let fw = zip(fwr, fwi).map { Complex<Double>(real: $0, imaginary: $1) } // complexN 2
let cc = zip(fg, fw).map { $0 * $1 } // multiply above 2 complex numbers fg * fw
var ccR = cc.map { $0.real } // real part (vector) of complex multiply
var ccI = cc.map { $0.imaginary } // imag part (vector) of complex multiply
let lc = nfft - ccR.count
let pad3: [Double] = Array(repeating: 0, count: lc) // 3rd zero padding
ccR += pad3
ccI += pad3
let (ggr, ggi) = fft(x: ccR, y: ccI, type: "ifft") // 3rd FFT (IFFT)
var GGr = [Double]()
var GGi = [Double]()
var W2r = [Double]()
var W2i = [Double]()
for v in 0 ..< M.count {
GGr.append(ggr[Int(M[v] - 1)])
GGi.append(ggi[Int(M[v] - 1)])
W2r.append(WR[Int(M[v] - 1)])
W2i.append(WI[Int(M[v] - 1)])
}
let ggg = zip(GGr, GGi).map { Complex<Double>(real: $0, imaginary: $1) }
let www = zip(W2r, W2i).map { Complex<Double>(real: $0, imaginary: $1) }
let y = zip(ggg, www).map { $0 * $1 }
let yR = y.map { $0.real } // FFT real part (output vector)
let yI = y.map { $0.imaginary } // FFT imag part (output vector)
return (yR, yI)
}
// END DFT BASED ON CHIRP Z TRANSFORM (CZT)
// CHIRP DFT (CZT) TEST
let x: [Double] = [1, 2, 3, 4, 5] // arbitrary sample size
let (fftR, fftI) = dft(x: x)
print("DFT Real Part:", fftR)
print(" ")
print("DFT Imag Part:", fftI)
// Matches Matlab FFT Output
// DFT Real Part: [15.0, -2.5000000000000018, -2.5000000000000013, -2.4999999999999991, -2.499999999999996]
// DFT Imag Part: [-1.1102230246251565e-16, 3.4409548011779334, 0.81229924058226477, -0.81229924058226599, -3.4409548011779356]
// END CHIRP DFT (CZT) TEST
Posting my comment as an answer to close this question—
If you’re sure you want to use an ICZT as an equivalent of IFFT, then make your dft function accept a type: String argument like your fft. When type is ifft, all you need is to flip the sign here:
WI.append(sin(-p1[i] * 2.0 * M_PI / Double(m)))
Leave it negative for forward FFT, and positive for inverse FFT (IFFT).
Here’s some Octave/Matlab code I wrote to demonstrate CZT: gist.github.com/fasiha/42a21405de92ea46f59e. The demo shows how to use czt2 to do fft. The third argument to czt2 (called w in the code) is exp(-2j * pi / Nup) for FFT. Just conjugate it to exp(+2j * pi / Nup) to get IFFT.
That’s what flipping the sign in the sin in WI does.

How to determine Y Axis values on a chart

I'm working on a charting algorithm that will give me a set n array of y axis values I would use on my graph.
The main problem is that I also want to calculate the number of number of steps to use and also use nice numbers for them. It must be able to take integers and doubles and be able to handle small ranges (under 1) and large ranges (over 10000 etc).
For example, if I was given a range of 0.1 - 0.9, ideally i would have values of 0, 0.2, 0.4, 0.6, 0.8, 1 but if I were given 0.3 to 0.7 I might use 0.3, 0.4, 0.5, 0.6, 0.7
This is what I have so far, it works well with small ranges, but terribly in large ranges, and doesn't give me nice numbers
-(double*)yAxisValues:(double)min (double):max {
double diff = max - min;
double divisor = 1.0;
if (diff > 1) {
while (diff > 1) {
diff /= 10;
divisor *= 10;
}
} else {
while (diff < 1) {
diff *= 10;
divisor *= 10;
}
}
double newMin = round(min * divisor) / divisor;
double newMax = round(max * divisor) / divisor;
if (newMin > min) {
newMin -= 1.0/divisor;
}
if (newMax < max) {
newMax += 1.0/divisor;
}
int test2 = round((newMax - newMin) * divisor);
if (test2 >= 7) {
while (test2 % 6 != 0 && test2 % 5 != 0 && test2 % 4 != 0 && test2 % 3 != 0) {
test2++;
newMax += 1.0/divisor;
}
}
if (test2 % 6 == 0) {
test2 = 6;
} else if (test2 % 5 == 0) {
test2 = 5;
} else if (test2 % 4 == 0 || test2 == 2) {
test2 = 4;
} else if (test2 % 3 == 0) {
test2 = 3;
}
double *values = malloc(sizeof(double) * (test2 + 1));
for (int i = 0; i < test2 + 1; i++) {
values[i] = newMin + (newMax - newMin) * i / test2;
}
return values;
}
Any suggestions?
Here's a snippet of code that does something similar, though has a slightly different approach. The "units" refer to what your are plotting on the graph. So if your scale is so that one unit on your graph should be 20 pixels on screen, this function would return how many units each step should be. With that information you can then easily calculate what the axis values are and where to draw them.
- (float)unitsPerMajorGridLine:(float)pixelsPerUnit {
float amountAtMinimum, orderOfMagnitude, fraction;
amountAtMinimum = [[self minimumPixelsPerMajorGridLine] floatValue]/pixelsPerUnit;
orderOfMagnitude = floor(log10(amountAtMinimum));
fraction = amountAtMinimum / pow(10.0, orderOfMagnitude);
if (fraction <= 2) {
return 2 * pow(10.0, orderOfMagnitude);
} else if (fraction <= 5) {
return 5 * pow(10.0, orderOfMagnitude);
} else {
return 10 * pow(10.0, orderOfMagnitude);
}
}
Simple adaptation for JavaScript (thanks a lot to Johan Kool for source)
const step = (() => {let pixelPerUnit = height / (end - size)
, amountAtMinimum = minimumPixelsPerMajorGridLine / pixelPerUnit
, orderOfMagnitude = Math.floor(Math.log10(amountAtMinimum))
, fraction = amountAtMinimum / Math.pow(10.0, orderOfMagnitude);
let result;
if (fraction <= 2) {
result = 2 * Math.pow(10.0, orderOfMagnitude);
} else if (fraction <= 5) {
result = 5 * Math.pow(10.0, orderOfMagnitude);
} else {
result = 10 * Math.pow(10.0, orderOfMagnitude);
}})();
let arr = [];
arr.push(start);
let curVal = start - start % step + step
, pxRatio = height / (end - start);
while (curVal < end) {
arr.push(curVal);
curVal += step;
}
arr.push(end);