Swift randomFloat issue: '4294967295' is not exactly representable as 'Float' [duplicate] - swift

This question already has an answer here:
Need explanation about random function swift
(1 answer)
Closed 3 years ago.
When generating a random CGFloat, I use the following code. Some explanation here
extension CGFloat{
static func randomFloat(from:CGFloat, to:CGFloat) -> CGFloat {
let randomValue: CGFloat = CGFloat(Float(arc4random()) / 0xFFFFFFFF)
return randomValue * (to - from ) + from
}
}
It used to be OK. Works fine now.
There is a warning, after I upgraded to Swift 5.
'4294967295' is not exactly representable as 'Float'; it becomes '4294967296'
to the line of code
let randomValue: CGFloat = CGFloat(Float(arc4random()) / 0xFFFFFFFF)
How to fix it?

As you know Float has only 24-bits of significand, so 32-bit value 0xFFFFFFFF would be truncated. So, Swift is warning to you that Float cannot represent the value 0xFFFFFFFF precisely.
The short fix would be something like this:
let randomValue: CGFloat = CGFloat(Float(arc4random()) / Float(0xFFFFFFFF))
With using Float.init explicitly, Swift would not generate such warnings.
But the preferred way would be using random(in:) method as suggested in matt's answer:
return CGFloat(Float.random(in: from...to))
or simply:
return CGFloat.random(in: from...to)

Simplest solution: abandon your code and just call https://developer.apple.com/documentation/coregraphics/cgfloat/2994408-random.

Related

Rules for type check in Swift builds?

I’ve wanted to speed up my build times, so one of the steps was using Other Swift Flags and
-Xfrontend -warn-long-function-bodies=100
-Xfrontend -warn-long-expression-type-checking=100
But I’m not really sure how type checks work. For example, here’s a simple func for creating random CGFloat. Type check for it is over 200ms
static func randomColorValue() -> CGFloat {
return CGFloat(Int.random(in: 0...255))/255.0
}
But on changing to something like this
static func randomColorValue() -> CGFloat {
let rnd = Int.random(in: 0...255)
let frnd = CGFloat(rnd)
let result = frnd/255.0
return result
}
or like this
static func randomColorValue() -> CGFloat {
let rnd : Int = Int.random(in: 0...255)
let frnd : CGFloat = CGFloat(rnd)
let result : CGFloat = frnd/255.0
return result
}
type check is still over 200ms.
What's wrong here? Is there any set of rules and best practices for dealing with build times?
My Mac is a bit older (2012), maybe that's the problem?
EDIT:
After turning off -warn-long-function-bodies problematic line appeared, and that is
CGFloat(rnd)
It appears that casting Int to Float, Double or CGFloat shows slowing down of 150ms.
Note that warn-long-function-bodies is unsupported (it was added as an experimental flag). If you remove it, I find that the expression time is often reported as twice as fast, which makes be believe that using the two measurements together is causing interference. Measurement takes time, too. warn-long-expression is a supported option.

Cannot match values of type

I'm just starting out with Swift 3 and I'm converting a Rails project to swift (side project while I learn)
Fairly simple, I have a Rails statement Im converting and Im getting many red errors in Xcode:
let startingPoint: Int = 1
let firstRange: ClosedRange = (2...10)
let secondRange: ClosedRange = (11...20)
func calc(range: Float) -> Float {
switch range {
case startingPoint:
return (range - startingPoint) * 1 // or 0.2
case firstRange:
return // code
default:
return //code
}
}
calc will either have an Int or Float value: 10 or 10.50
Errors are:
Expression pattern of type ClosedRange cannot match values of type Float
Binary operator - cannot be applied to operands of type Float and Int
I understand the errors but I dont know what to search for to correct it. Could you point me in the right direction, please?
Swift is strongly typed. Whenever you use a variable or pass something as a function argument, Swift checks that it is of the correct type. You can't pass a string to a function that expects an integer etc. Swift does this check at compile time (since it's statically typed).
To adhere by that rules, try changing your code to this:
let startingPoint: Float = 1
let firstRange: ClosedRange<Float> = (2...10)
let secondRange: ClosedRange<Float> = (11...20)
func calc(range: Float) -> Float {
switch range {
case startingPoint:
return (range - startingPoint) * 1 // or 0.2
case firstRange:
return 1.0 // 1.0 is just an example, but you have to return Float since that is defined in the method
default:
return 0.0 // 0.0 is just an example, put whatever you need here
}
}
For the first error, you might want to specify ClosedRange to be of type Floats. Something similar to:
let firstRange: ClosedRange<Float> = (2...10)
For the second error, the problem is you are trying to compare a Float (range:Float) with an Int (startingPoint). So I would suggest you convert the startingPoint variable to a Float as well.

How to round the double to decimal places value in Swift 3? [duplicate]

I have the following simple extension to Double, which worked fine in everything up to Xcode 8 beta 3
public extension Double {
public func roundTo(_ decimalPlaces: Int) -> Double {
var v = self
var divisor = 1.0
if decimalPlaces > 0 {
for _ in 1 ... decimalPlaces {
v *= 10.0
divisor *= 0.1
}
}
return round(v) * divisor
}
}
As of Beta 4, I am getting "Cannot use mutating member on immutable value: 'self' is immutable" on the round function in the return - has anyone got any clues?
This is due to a naming conflict with the new rounding functions on the FloatingPoint protocol, round() and rounded(), which have been added to Swift 3 as of Xcode 8 beta 4.
You therefore either need to disambiguate by specifying that you're referring to global round() function in the Darwin module:
return Darwin.round(v) * divisor
Or, even better, simply make use of the new rounding functions and call rounded() on v:
return v.rounded() * divisor

Swift 3 Migration - Double Extension rounding issue

I'm migrating our codebase to Swift 3 and I've come across a compilation issue that I can't explain or fix.
I have a method in a Double extension that rounds the Double to a certain number of digits:
public func roundToPlaces(places: Int) -> Double {
let divisor = pow(10.0, Double(places))
return round(self * divisor) / divisor
}
For example:
12.34567.roundToPlaces(2) should return 12.35. However, I'm getting a compilation issue for the round method used in this extension. It's saying that I Cannot use mutating member on immutable value: 'self' is immutable.
Any ideas on what's going on here? How do I fix this issue?
I've fixed the issue. Changing round(self * divisor) to (self * divisor).rounded() resolved the compilation issue.

CGFloat <-> Double

Writing graphics code in UIKit is a PITA. The "nominal" floating point type for Swift is Double. But most of the UIKit graphics code uses CGFloat which seems to be either Double or Float based on the chip in my phone. I find myself having to constantly use CGFloat() and Double() transformers.
I have considered killing the problem by simply providing the operators it continually complains are lacking (I like to add lots of numeric type extensions anyway):
func * (lhs:CGFloat, rhs:Double) -> Double {
return Double(lhs) * rhs
}
func * (lhs:CGFloat, rhs:Double) -> CGFloat {
return lhs * CGFloat(rhs)
}
func * (lhs:Double, rhs:CGFloat) -> Double {
return lhs * Double(rhs)
}
func * (lhs:Double, rhs:CGFloat) -> CGFloat {
return CGFloat(lhs) * rhs
}
With this in place, I don't have to care anymore. I realize there will be lots of opinions as to whether this is a good thing or not. I get the cases where there can be subtle differences between a CGFloat that is a Float on a 32 bit platform and a Double, but I'm not sure that I'm likely to see them anyway. In other words, I can do this once and only once and get stung by those edge cases where fp math breaks down at the boundaries, or I can constantly convert things a million times over and still get stung by the same edge case. So my question is, is there ANY OTHER reason than those edge cases of fp math, not to do this?