Adding float numbers to Decimal numbers - ios

I have this code:
var weightSum: Float = 3.14159
let weightPerPortionGrams: Decimal = 0.999999
weightSum = weightSum + (weightPerPortionGrams)
The numbers are examples.
I get an error:
Binary operator '+ =' can not be applied to type 'Float' and 'Decimal'.
Does anyone know how to fix it?

To convert a Decimal to a float, you can either do this:
weightSum += Float(truncating: weightPerPortionGrams as NSNumber)
or this:
weightSum += (weightPerPortionGrams as NSNumber).floatValue

Swift needs both variables to be of the same type to make use of the "+" operator, so you would need to either convert your Decimal to type Float or the other way around before summing them:
weightPerPortionGramsFloat = (weightPerPortionGrams as NSNumber).floatValue
or
weightSumDecimal = (weightSum as NSNumber).decimalValue

Greetings!
func + (left: Float, right: Decimal) -> Float {
return left + Float(right.description)!
}
var weightSum: Float = 3.14159
let weightPerPortionGrams: Decimal = 0.999999
weightSum = weightSum + weightPerPortionGrams
print(weightSum)
// prints 4.141589
Hope it helps!

This is because the variables weightSum and weightPerPortionGrams have different types. Luckily you can convert these variables in Swift.
So, to make this work, you should convert the type of weightPerPortionGrams to the one of weightSum, so both variables become the same type:
weightSum = weightSum + NSDecimalNumber(decimal: weightPerPortionGrams).floatValue
Note that Decimal might not handle the floating points quite well.
You can also do an extra cast, to make sure that we are using the methods of NSDecimalNumber and not of NSNumber:
let double = NSDecimalNumber(decimal: weightPerPortionGrams).doubleValue
weightSum = weightSum + Float(double)

Related

Is there any way to iterate the decimal part of a double var in swift 4?

What i'm looking for:
Given a Double (doublenumber) and an Int (n) I wish to iterate trough the 1st decimal, 2nd decimal, 3rd decimal, 4th decimal.... until the 'n'decimal
My first approach was, coverting to String the Double so I could iterate like an array the string, but the problem is that when I convert to string I lose many decimals numbers
let doubleNumber = 1.00/98 //0.010204081632653061224489795918367346938775510204081632653...
var stringFromDouble = String(doubleNumber) //0.010204081632653
stringFromDouble.removeFirst() //.010204081632653
stringFromDouble.removeFirst() //010204081632653
for letter in stringFromDouble{
//cycle to iterate the decimals
}
If the intention is to get many decimal digits of 1.0/98.0 then you must not store that number in a Double in the first place, because that has a precision of approximately 16 decimal digits only. You could use Decimal which has a precision of 38 decimal digits.
But for more decimal digits you'll have to do “rational arithmetic,” i.e. work with numerator and denominator of the fraction as integers.
Here is how you can print arbitrarily many decimal digits of a rational number. For simplicity I have assumed that the number is positive and less than one.
func printDecimalDigits(of numerator: Int, dividedBy denominator: Int, count: Int) {
var numerator = numerator
for _ in 1...count {
// Multiply by 10 to get the next digit:
numerator *= 10
// Print integer part of `numerator/denominator`:
print(numerator / denominator, terminator: "")
// Reduce `numerator/denominator` to its fractional part:
numerator %= denominator
}
print()
}
Example:
printDecimalDigits(of: 1, dividedBy: 98, count: 100)
// 0102040816326530612244897959183673469387755102040816326530612244897959183673469387755102040816326530
Or as a function which returns the digits as a (lazily evaluated) sequence:
func decimalDigits(of numerator: Int, dividedBy denominator: Int) -> AnySequence<Int> {
return AnySequence(sequence(state: numerator) { num -> Int in
num *= 10
let d = num / denominator
num %= denominator
return d
})
}
Example:
let first1000Digits = decimalDigits(of: 1, dividedBy: 98).prefix(1000)
for d in first1000Digits { print(d) }

How can I split a float (1,2) into 1 and 2 integers?

I'm learning F# and have an assignment where I have to treat a float as a coordinate. For example float 2.3 would be treated as a coordinate (2.3) where x is 2 and y is 3.
How can I split the float to calculate with it?
I am trying to make a function to calculate the length of a vector:
let lenOfVec (1.2, 2.3) and using pythagoras' method to get the length of hypotenuse.
But I am already stuck at splitting up the float.
Hope some can help!
Having at your disposal libraries as rich as F#/.NET offer the task of splitting a float into two can be done with one short line of code:
let splitFloat n = n.ToString().Split('.') |> Array.map float
library function ToString() converts the argument n (supposedly float) to a string
library functionSplit('.') applied to this string converts it into an array of two strings representing the first number before decimal dot and the second number after the dot
finally this array of 2 strings is converted by applying library function float to the each array element with the help of just another library function Array.map, producing the array of two sought floats
Being applied to a random float number the outlined chain of conversions looks like
123.456 --> "123.456" --> [|123;456|] --> [|123.0;456.0|]
Stealing from a few other answers on here, something like this seems to work for a few examples:
open System
///Takes in a float and returns a tuple of the the two parts.
let split (n: float) =
let x = Math.Truncate(n)
let bits = Decimal.GetBits(decimal n)
let count = BitConverter.GetBytes(bits.[3]).[2]
let dec = n - x
let y = dec * Math.Pow(10., float count)
x, y
Examples:
2.3 -> (2.0, 3.0)
200.123 -> (200.0, 123.0)
5.23 -> (5.0, 23.0)
Getting the X is easy, as you can just truncate the decimal part.
Getting the Y took input from this answer and this one.

What does "% is unavailable: Use truncatingRemainder instead" mean?

I get the following error when using code for an extension, I'm not sure if they're asking to just use a different operator or modify the values in the expression based on an internet search.
Error: % is unavailable: Use truncatingRemainder instead
Extension code:
extension CMTime {
var durationText:String {
let totalSeconds = CMTimeGetSeconds(self)
let hours:Int = Int(totalSeconds / 3600)
let minutes:Int = Int(totalSeconds % 3600 / 60)
let seconds:Int = Int(totalSeconds % 60)
if hours > 0 {
return String(format: "%i:%02i:%02i", hours, minutes, seconds)
} else {
return String(format: "%02i:%02i", minutes, seconds)
}
}
}
The error(s) occur when setting the minutes and seconds variables.
CMTimeGetSeconds() returns a floating point number (Float64 aka
Double). In Swift 2 you could compute the
remainder of a floating point division as
let rem = 2.5 % 1.1
print(rem) // 0.3
In Swift 3 this is done with
let rem = 2.5.truncatingRemainder(dividingBy: 1.1)
print(rem) // 0.3
Applied to your code:
let totalSeconds = CMTimeGetSeconds(self)
let hours = Int(totalSeconds / 3600)
let minutes = Int((totalSeconds.truncatingRemainder(dividingBy: 3600)) / 60)
let seconds = Int(totalSeconds.truncatingRemainder(dividingBy: 60))
However, in this particular case it is easier to convert the duration
to an integer in the first place:
let totalSeconds = Int(CMTimeGetSeconds(self)) // Truncate to integer
// Or:
let totalSeconds = lrint(CMTimeGetSeconds(self)) // Round to nearest integer
Then the next lines simplify to
let hours = totalSeconds / 3600
let minutes = (totalSeconds % 3600) / 60
let seconds = totalSeconds % 60
The % modulus operator is defined only for integer types. For floating-point types, you need to be more specific about the kind of IEEE 754 division/remainder behavior you want, so you have to call a method: either remainder or truncatingRemainder. (If you're doing floating-point math you actually need to care about this, and lots of other stuff, or you can get unexpected / bad results.)
If you actually intend to do integer modulus, you need to convert the return value of CMTimeGetSeconds to an integer before using %. (Note that if you do, you'll lop off the fractional seconds... depending on where you're using CMTime that may be important. Do you want minutes:seconds:frames, for example?)
Depending on how you want to present CMTime values in your UI, it might be better to extract the seconds value and pass it to NSDateFormatter or NSDateComponentsFormatter so you get appropriate locale support.
Bring back the simple modulo syntax in swift 3:
This syntax was actually suggested on Apples official swift mailing list here but for some reason they opted for a less elegant syntax.
infix operator %%/*<--infix operator is required for custom infix char combos*/
/**
* Brings back simple modulo syntax (was removed in swift 3)
* Calculates the remainder of expression1 divided by expression2
* The sign of the modulo result matches the sign of the dividend (the first number). For example, -4 % 3 and -4 % -3 both evaluate to -1
* EXAMPLE:
* print(12 %% 5) // 2
* print(4.3 %% 2.1) // 0.0999999999999996
* print(4 %% 4) // 0
* NOTE: The first print returns 2, rather than 12/5 or 2.4, because the modulo (%) operator returns only the remainder. The second trace returns 0.0999999999999996 instead of the expected 0.1 because of the limitations of floating-point accuracy in binary computing.
* NOTE: Int's can still use single %
* NOTE: there is also .remainder which supports returning negatives as oppose to truncatingRemainder (aka the old %) which returns only positive.
*/
public func %% (left:CGFloat, right:CGFloat) -> CGFloat {
return left.truncatingRemainder(dividingBy: right)
}
This simple swift 3 migration tip is part of a more comprehensive swift 3 migration guide with many insights (35k loc / 8-days of migration) http://eon.codes/blog/2017/01/12/swift-3-migration/
There's no need to create a separate modulo operator for floating point numbers, unless you think it makes the code safer. You can overload the % operator to accept floating point numbers like so:
func %<N: BinaryFloatingPoint>(lhs: N, rhs: N) -> N {
lhs.truncatingRemainder(dividingBy: rhs)
}
Usage
let a: Float80 = 10
let b: Float80 = 3
print(a % b)
You can now use % with any two floating point numbers of the same tye.
I found that the following works in Swift 3:
let minutes = Int(floor(totalSeconds / 60))
let seconds = Int(totalSeconds) % 60
where totalSeconds is a TimeInterval (Double).

Why does the xcode say "Expression was too complex to be solved in reasonable time..." for my Swift code?

I am writing an app, and I have a block of code that reads like this:
let DestViewController: ftrViewController = segue.destinationViewController as! ftrViewController
let weightInt: Int? = Int(weightInKilos.text!)
let dehydrationInt: Int? = Int(percentOfDehydration.text!)
let lossesInt: Int? = Int(ongoingLosses.text!)
let factorFloat: Float? = Float(Factor.text!)
let lrs24Int = (30 * weightInt! + 70) * factorFloat! + weightInt! * dehydrationInt! * 10 + lossesInt!
However, Xcode says that Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions.
My equation looks right to me, and I do not believe that my equation is too complex, because I had the same error when the problem was simply that I wasn't declaring the integers correctly (the deal with the ?s and the !s).
Does anybody see a problem in my code that is leading to this error, or is the expression truly too hard for the computer to solve in reasonable time? Thanks!
PS- I think the problem might be the float, because before I added the float, it was working fine.
Rewritten Code
let weightInt: Float? = Float(weightInKilos.text!)
let dehydrationInt: Float? = Float(percentOfDehydration.text!)
let lossesInt: Float? = Float(ongoingLosses.text!)
let factorFloat: Float? = Float(Factor.text!)
let step1 = (30 * weightInt! + 70) * factorFloat! + weigh
let lrs24Int = step1 * dehydrationInt! * 10 + lossesInt!
It was not Only Float problem. I used float to avoid type conversions as all are float. The Main Problem was the Complexity of expression.

List comprehensions with float iterator in F#

Consider the following code:
let dl = 9.5 / 11.
let min = 21.5 + dl
let max = 40.5 - dl
let a = [ for z in min .. dl .. max -> z ] // should have 21 elements
let b = a.Length
"a" should have 21 elements but has got only 20 elements. The "max - dl" value is missing. I understand that float numbers are not precise, but I hoped that F# could work with that. If not then why F# supports List comprehensions with float iterator? To me, it is a source of bugs.
Online trial: http://tryfs.net/snippets/snippet-3H
Converting to decimals and looking at the numbers, it seems the 21st item would 'overshoot' max:
let dl = 9.5m / 11.m
let min = 21.5m + dl
let max = 40.5m - dl
let a = [ for z in min .. dl .. max -> z ] // should have 21 elements
let b = a.Length
let lastelement = List.nth a 19
let onemore = lastelement + dl
let overshoot = onemore - max
That is probably due to lack of precision in let dl = 9.5m / 11.m?
To get rid of this compounding error, you'll have to use another number system, i.e. Rational. F# Powerpack comes with a BigRational class that can be used like so:
let dl = 95N / 110N
let min = 215N / 10N + dl
let max = 405N / 10N - dl
let a = [ for z in min .. dl .. max -> z ] // Has 21 elements
let b = a.Length
Properly handling float precision issues can be tricky. You should not rely on float equality (that's what list comprehension implicitely does for the last element). List comprehensions on float are useful when you generate an infinite stream. In other cases, you should pay attention to the last comparison.
If you want a fixed number of elements, and include both lower and upper endpoints, I suggest you write this kind of function:
let range from to_ count =
assert (count > 1)
let count = count - 1
[ for i = 0 to count do yield from + float i * (to_ - from) / float count]
range 21.5 40.5 21
When I know the last element should be included, I sometimes do:
let a = [ for z in min .. dl .. max + dl*0.5 -> z ]
I suspect the problem is with the precision of floating point values. F# adds dl to the current value each time and checks if current <= max. Because of precision problems, it might jump over max and then check if max+ε <= max (which will yield false). And so the result will have only 20 items, and not 21.
After running your code, if you do:
> compare a.[19] max;;
val it : int = -1
It means max is greater than a.[19]
If we do calculations the same way the range operator does but grouping in two different ways and then compare them:
> compare (21.5+dl+dl+dl+dl+dl+dl+dl+dl) ((21.5+dl)+(dl+dl+dl+dl+dl+dl+dl));;
val it : int = 0
> compare (21.5+dl+dl+dl+dl+dl+dl+dl+dl+dl) ((21.5+dl)+(dl+dl+dl+dl+dl+dl+dl+dl));;
val it : int = -1
In this sample you can see how adding 7 times the same value in different order results in exactly the same value but if we try it 8 times the result changes depending on the grouping.
You're doing it 20 times.
So if you use the range operator with floats you should be aware of the precision problem.
But the same applies to any other calculation with floats.

Resources