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

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

Related

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

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.

'+' is deprecated: Mixed-type addition is deprecated in Swift 3.1

When I'm directly adding an integer value(i.e: 1,2,3,etc) with another integer variable
let arr:Array = ["One","Two"]
var valueT:Int64 = 0
value = arr.count + 1 //in this line
I get the following warning:
'+' is deprecated: Mixed-type addition is deprecated. Please use explicit type conversion.
I fixed it the warning with this:
value = Int64(value + 1)
Though it is fixed but I wanna know why its called Mixed-type addition as I didn't use ++ . Also is there a better way to fix the warning in swift 3.1?
Update:
The following image is the proof of warning. I'm using Xcode Version 8.3 (8E162).
allROR is an array here.
Edit: To generate the error with your code it should be like
let value = 5
let result: Int64 = value + 1
Now you get the warning
'+' is deprecated: Mixed-type addition is deprecated. Please use explicit type conversion.
But it is looks like warning is misleading, as of both value and 1 is of type Int so its summation also Int so you need to simply convert the result to Int64 and it is what you doing and that is perfectly ok.
let result: Int64 = Int64(value + 1)
Just to answer this part: why its called Mixed-type addition
With the simplified example by Nirav D:
let value = 5
let result: Int64 = value + 1
You can Command-click on + and see the generated interface of Collection:
(After Indexing has finished, of course.)
#available(swift, deprecated: 3.0, obsoleted: 4.0, message: "Mixed-type addition is deprecated. Please use explicit type conversion.")
public func +<T>(lhs: T.Stride, rhs: T) -> T where T : SignedInteger
So, in the code example above, the type of 1 is inferred as Int64, and as Int64.Stride == Int, the operation value + 1 matches the signature func +<T>(lhs: T.Stride, rhs: T) -> T where T : SignedInteger.
This deprecation is included in the revised version of SE-0104 Protocol-oriented integers, this part:
Standard Library no longer provides + and - operators for Strideable types.
They were problematic, as one could have written mixed-type code like
let x: Int64 = 42; x += (1 as Int), which would compile, but
shouldn't. Besides, since the Stride of an unsigned type is signed,
Standard Library had to implement a hack to make code like let x: UInt
= 42; x += (1 as Int) ambiguous. These operators were only necessary because they made advancing collection indices convenient, which is no
longer the case since the introduction of the new indexing model in
Swift 3.
As you already have seen, you can avoid this warning in many ways.
Data type is different that is why it is showing an error
you need to make both variable and constant of same data type
for e.g.
let result = value + Int64(1) //in this line
OK
var arr = [String]()
var i: Int64 = 0
if arr.count == 0 {
i = 1
} else {
i = arr.count + 1
}
gives as a warning '+' is deprecated: Mixed-type addition is deprecated. Please use explicit type conversion.
The reason is, that arr.count and i has different types. And this warning is right. It has nothing with the integer literal 1
this snippet gives you the warning too
var arr = [String]()
var i: Int64 = 0
if arr.count == 0 {
i = 1
} else {
i = 1
i += arr.count // here is the warning now
}
this will not compile, even though it looks very similar
var arr = [String]()
var i: Int64 = 0
if arr.count == 0 {
i = 1
} else {
let tmp = arr.count + 1
i = tmp
}
I hope we get an error message when we compose all of these snippets in the future release.

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.

No * candidates produce the expected contextual result type 'FloatingPointRoundRule' [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.