Round Half Down in Swift - swift

Is there a rounding mode in Swift that behaves same as ROUND_HALF_DOWN in Java?
Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round down. Behaves as for RoundingMode.UP if the discarded fraction is > 0.5; otherwise, behaves as for RoundingMode.DOWN.
Example:
2.5 rounds down to 2.0
2.6 rounds up to 3.0
2.4 rounds down to 2.0
For a negative number:
-2.5 rounds up to -2.0
-2.6 rounds down to -3.0
-2.4 rounds up to -2.0

There is – as far as I can tell – no FloatingPointRoundingRule with the same behavior as Java's ROUND_HALF_DOWN, but you can get the result with a combination of rounded() and nextDown or nextUp:
func roundHalfDown(_ x: Double) -> Double {
if x >= 0 {
return x.nextDown.rounded()
} else {
return x.nextUp.rounded()
}
}
Examples:
print(roundHalfDown(2.4)) // 2.0
print(roundHalfDown(2.5)) // 2.0
print(roundHalfDown(2.6)) // 3.0
print(roundHalfDown(-2.4)) // -2.0
print(roundHalfDown(-2.5)) // -2.0
print(roundHalfDown(-2.6)) // -3.0
Or as a generic extension method, so that it can be used with all floating point types (Float, Double, CGFloat):
extension FloatingPoint {
func roundedHalfDown() -> Self {
return self >= 0 ? nextDown.rounded() : nextUp.rounded()
}
}
Examples:
print((2.4).roundedHalfDown()) // 2.0
print((2.5).roundedHalfDown()) // 2.0
print((2.6).roundedHalfDown()) // 3.0
print((-2.4).roundedHalfDown()) // -2.0
print((-2.5).roundedHalfDown()) // -2.0
print((-2.6).roundedHalfDown()) // -3.0

Swift implements .round() function with rules, According to Apple
FloatingPointRoundingRule
case awayFromZero
Round to the closest allowed value whose magnitude is greater than or equal to that of the source.
case down
Round to the closest allowed value that is less than or equal to the source.
case toNearestOrAwayFromZero
Round to the closest allowed value; if two values are equally close, the one with greater magnitude is chosen.
case toNearestOrEven
Round to the closest allowed value; if two values are equally close, the even one is chosen.
case towardZero
Round to the closest allowed value whose magnitude is less than or equal to that of the source.
case up
Round to the closest allowed value that is greater than or equal to the source.

Yes, You can do the similar things using NSNumberFormatter and RoundingMode
Read them here
NSNumberFormatter
RoundingMode

var a = 6.54
a.round(.toNearestOrAwayFromZero)
// a == 7.0
var b = 6.54
b.round(.towardZero)
// b == 6.0
var c = 6.54
c.round(.up)
// c == 7.0
var d = 6.54
d.round(.down)
// d == 6.0
You can do like this as well but need to take values after decimal as well.

As #MohmmadS said those are built in methods for rounding.
You can implement custom rounding like this:
func round(_ value: Double, toNearest: Double) -> Double {
return round(value / toNearest) * toNearest
}
func roundDown(_ value: Double, toNearest: Double) -> Double {
return floor(value / toNearest) * toNearest
}
func roundUp(_ value: Double, toNearest: Double) -> Double {
return ceil(value / toNearest) * toNearest
}
Example:
round(52.376, toNearest: 0.01) // 52.38
round(52.376, toNearest: 0.1) // 52.4
round(52.376, toNearest: 0.25) // 52.5
round(52.376, toNearest: 0.5) // 52.5
round(52.376, toNearest: 1) // 52

Related

Need explanation about random function swift

Got a question about my random function: why is it giving this error?
'4294967295' is not exactly representable as 'Float'; it becomes '4294967296'
-
my code is
func random() ->CGFloat {
return CGFloat(Float(arc4random()) / 0xFFFFFFFF)
}
func random(min: CGFloat, max: CGFloat) -> CGFloat {
return random() * (max - min) + min
}
it doesn't change the functionality of the application but it just appeared out of nowhere.
thanks in advance!
A IEEE 754 32-bit floating point number has 24 significant bits for the mantissa, that is not enough to store a 10-digit integer exactly:
print(0xFFFFFFFF) // 4294967295
print(Float(0xFFFFFFFF)) // 4.2949673e+09
print(Int(Float(0xFFFFFFFF))) // 4294967296
That won't affect your code because
Float(arc4random()) / Float(0xFFFFFFFF)
is still a floating point number between 0.0 and 1.0. Changing the calculation to
return CGFloat(arc4random()) / 0xFFFFFFFF
will fix the warning on 64-bit platforms: The integer constant is now converted to a (64-bit) Double.
But as of Swift 4.2 you can avoid the problem completely by using the new Random API:
func random(min: CGFloat, max: CGFloat) -> CGFloat {
return CGFloat.random(in: min...max)
}

Receiving NaN as an output when using the pow() function to generate a Decimal

I've been at this for hours so forgive me if I'm missing something obvious.
I'm using the pow(_ x: Decimal, _ y: Int) -> Decimal function to help generate a monthly payment amount using a basic formula. I have this function linked to the infix operator *** but I've tried using it just by typing out the function and have the same problem.
Xcode was yelling at me yesterday for having too long of a formula, so I broke it up into a couple constants and incorporated that into the overall formula I need.
Code:
precedencegroup PowerPrecedence { higherThan: MultiplicationPrecedence }
infix operator *** : PowerPrecedence
func *** (radix: Decimal, power: Int) -> Decimal {
return (pow((radix), (power)))
}
func calculateMonthlyPayment() {
let rateAndMonths: Decimal = ((0.0199 / 12.0) + (0.0199 / 12.0))
let rateTwo: Decimal = ((1.0+(0.0199 / 12.0)))
loan12YearsPayment[0] = ((rateAndMonths / rateTwo) *** 144 - 1.0) * ((values.installedSystemCost + loanFees12YearsCombined[0]) * 0.7)
When I print to console or run this in the simulator, the output is NaN. I know the pow function itself is working properly because I've tried it with random integers.
Kindly find my point of view for this Apple function implementation, Note the following examples:
pow(1 as Decimal, -2) // 1; (1 ^ Any number) = 1
pow(10 as Decimal, -2) // NAN
pow(0.1 as Decimal, -2) // 100
pow(0.01 as Decimal, -2) // 10000
pow(1.5 as Decimal, -2) // NAN
pow(0.5 as Decimal, -2) // NAN
It seems like, pow with decimal don't consider any floating numbers except for 10 basis. So It deals with:
0.1 ^ -2 == (1/10) ^ -2 == 10 ^ 2 // It calculates it appropriately, It's 10 basis 10, 100, 1000, ...
1.5 ^ -2 == (3/2) ^ -2 // (3/2) is a floating number ,so deal with it as Double not decimal, It returns NAN.
0.5 ^ -2 == (1/2) ^ -2 // (2) isn't 10 basis, So It will be dealt as (1/2) as It is, It's a floating number also. It returns NAN.

Rounding Numbers to Two Significant Figures

I am sure this is an easy question to any of you are experienced in Swift, however, I just started learning how to program and have no idea where to start. What I am trying to do is a round a number to the nearest whole value, or to the third number. This is what I mean:
12.6 //Want rounded to 13
126 //Want rounded to 130
1264 //Want rounded to 1300
I know swift has a .rounded() function, and I have managed to use it to round the nearest 10th, 100th, etc., however, I cannot round the way I would like to. Any advice would be much appreciated.
Here's one way to round any Double or Int (including negative numbers) to a given number of significant figures:
func round(_ num: Double, to places: Int) -> Double {
let p = log10(abs(num))
let f = pow(10, p.rounded() - Double(places) + 1)
let rnum = (num / f).rounded() * f
return rnum
}
func round(_ num: Int, to places: Int) -> Int {
let p = log10(abs(Double(num)))
let f = pow(10, p.rounded() - Double(places) + 1)
let rnum = (Double(num) / f).rounded() * f
return Int(rnum)
}
print(round(0.265, to: 2))
print(round(1.26, to: 2))
print(round(12.6, to: 2))
print(round(126, to: 2))
print(round(1264, to: 2))
Output:
0.27
1.3
13.0
130
1300
As stated by Sulthan you can use NumberFormatter:
let formatter = NumberFormatter()
formatter.usesSignificantDigits = true
formatter.maximumSignificantDigits = 2
formatter.minimumSignificantDigits = 2
if let result = formatter.string(from: 12.6) {
print(result) // prints 13
}
One possibility to implement a rounding algorithm. I suppose you always want the result to be integer.
func round(_ number: Float, to digits: Int) -> Float {
guard number >= 0 else {
return -round(-number, to: digits)
}
let max = pow(10, Float(digits))
var numZeros = 0
var value = number
while (value >= max) {
value /= 10
numZeros += 1
}
return round(value) * pow(10, Float(numZeros))
}
print(round(12.6, to: 2)) // 13
print(round(126, to: 2)) // 130
print(round(1264, to: 2)) // 1300

How to generate a float between 1 and 100

I am trying to generate random floats between 1 and 100, but I keep getting errors everytime. Currently I am trying:
func returnDbl ()-> Double {
var randNum = Double(Float(arc4random(101) % 5))
return randNum
}
print(returnDbl())
but to no avail, would someone point me in the right direction?
arc4random is zero-based and returns values between 0 and n-1, pass 100 as the upper bounds and add 1
arc4random_uniform is easier to use, it returns an Int32 type which has to be converted to Float.
func randomFloat() -> Float {
return Float(arc4random_uniform(100) + 1)
}
or Double
func randomDouble() -> Double {
return Double(arc4random_uniform(100) + 1)
}
or generic
func returnFloatingPoint<T : FloatingPointType>()-> T {
return T(arc4random_uniform(100) + 1)
}
let float : Float = returnFloatingPoint()
let double : Double = returnFloatingPoint()
Edit
To return a non-integral Double between 1.000000 and 99.99999 with arc4random_uniform() use
func returnDouble()-> Double {
return Double(arc4random_uniform(UInt32.max)) / 0x100000000 * 99.0 + 1.0
}
0x100000000 is UInt32.max + 1
let a = 1 + drand48() * 99
drand48 is a C function that returns a double in the range [0, 1). You can call it directly from Swift. Multiplying by 99 gives you a double in the range [0, 99). Add one to get into the range [1, 100).
As drand48 returns a double, the Swift type will be Double.
As per the comment, drand48 will by default return the same sequence of numbers upon every launch. You can avoid that by seeding it. E.g.
seed48(UnsafeMutablePointer<UInt16>([arc4random(), arc4random()]))
func returnDbl ()-> Double {
var randNum = Double(Float(arc4random() % 101))
return randNum
}
Ok thank you everybody for all of your help, the setups you showed me helped me figure out how the setup should at least look, my end result is
func returnDbl ()-> Double{
var randNum = Double(Float(arc4random_uniform(99)+1)) / Double(UINT32_MAX)
return randNum
}
print(returnDbl())
it returns floats between 1 and 100.

Swift automatic function inversion

If I have a function like:
func evaluateGraph(sender: GraphView, atX: Double) -> Double? {
return function?(atX)
}
Where function is a variable declared earlier and it is a mathematical expression (like x^2). How can I find the inverse of the univariate function in swift at a point (atX)?
Assuming that you just want to know the inverse function in your GraphView (which is hopefully not infinite) you can use something like this:
// higher percision -> better accuracy, start...end: Interval, f: function
func getZero(#precision: Int, var #start: Double, var #end: Double, f: Double -> Double) -> Double? {
let fS = f(start)
let fE = f(end)
let isStartNegative = fS.isSignMinus
if isStartNegative == fE.isSignMinus { return nil }
let fMin = min(fS, fE)
let fMax = max(fS, fE)
let doublePrecision = pow(10, -Double(precision))
while end - start > doublePrecision {
let mid = (start + end) / 2
let fMid = f(mid)
if fMid < fMin || fMax < fMid {
return nil
}
if (fMid > 0) == isStartNegative {
end = mid
} else {
start = mid
}
}
return (start + end) / 2
}
// same as above but it returns an array of points
func getZerosInRange(#precision: Int, #start: Double, #end: Double, f: Double -> Double) -> [Double] {
let doublePrecision = pow(10, -Double(precision))
/// accuracy/step count between interval; "antiproportional" performance!!!!
let stepCount = 100.0
let by = (end - start) / stepCount
var zeros = [Double]()
for x in stride(from: start, to: end, by: by) {
if let xZero = getZero(precision: precision, start: x, end: x + by, f) {
zeros.append(xZero)
}
}
return zeros
}
// using currying; all return values should be elements of the interval start...end
func inverse(#precision: Int, #start: Double, #end: Double, f: Double -> Double)(_ x: Double) -> [Double] {
return getZerosInRange(precision: precision, start: start, end: end) { f($0) - x }
}
let f = { (x: Double) in x * x }
// you would pass the min and max Y values of the GraphView
// type: Double -> [Double]
let inverseF = inverse(precision: 10, start: -10, end: 10, f)
inverseF(4) // outputs [-1.999999999953436, 2.000000000046564]
Interestingly this code rund in a playground in about 0.5 second which I didn't expect.
You could create an inverse function to do the opposite.
So f(x) = y inverse f' gives f'(y) = x.
So if your defined function is to square the input then the inverse is to return the square root and so on.
You might run into trouble with something like that though as f'(1) = 1 and -1 in the case where f(x) returns the square.
Short of actually writing the inverse method, the only way to actually inversely infer what input gave a provided output, the best we can do is write our program to make guesses until it's within a certain accuracy.
So, for example, let's say we have the square function:
func square(input: Double) -> Double {
return input * input
}
Now, if we don't want to right the inverse of this function (which actually has two inputs for any given output), then we have to write a function to guess.
func inverseFunction(output: Double, function: (Double)->Double) -> Double
This takes a double representing the output, and a function (the one that generated the output), and returns its best-guess at the answer.
So, how do we guess?
Well, the same way we do in pre-calculus and the early parts of any calculus 1 class. Pick a starting number, run it through the function, compare the result to the output we're looking for. Record the delta. Pick a second number, run it through the function, compare the result to the output we're looking for. Record the delta, compare it to the first delta.
Continually do this until you have minimized the delta to an acceptable accuracy level (0.1 delta okay? 0.01? 0.0001?). The smaller the delta, the longer it takes to calculate. But it's going to take a long time no matter what.
As for the guessing algorithm? That's a math question that I'm not capable of answering. I wouldn't even know where to begin with that.
In the end, your best bet is to simply write inverse functions for any function you'd want to inverse.