Using arc4random_uniform to return a both whole and non whole doubles - swift

Using Swift, I am trying to figure out how to use arc4random_uniform to return a number like 37.7. The guidance I must abide by is I must do it in a function, the random double must be between 0 - 300. I have been able to build a function that randomly returns doubles between the range but can't find anything that will lead me to outputting random non whole numbers
//function to randomly generate a double number like 105.3
func makeRandDbl() -> Double {
let randGenerator: Double = Double(arc4random_uniform(301))
print(randGenerator)
return randGenerator
}
makeRandDb()

To generate a Double in the range 0.0 to 300.0 (with one digit following the decimal):
Double(arc4random_uniform(3001))/10.0
You can extend this to more decimal places. For two decimal places (0.00 to 300.00):
Double(arc4random_uniform(30001))/100.0
For three decimal places (0.000 to 300.000):
Double(arc4random_uniform(300001))/1000.0
This has the advantage of being able to actually generate whole values. In the first case 10% of the numbers will be whole. In the second case 1% of the numbers will be whole. And in the third, 0.1% of the numbers will be whole.

This is your function, I believe:
extension Double {
/// Generates a random `Double` within `0.0...1.0`
public static func random() -> Double {
return random(0.0...1.0)
}
/// Generates a random `Double` inside of the closed interval.
public static func random(interval: ClosedInterval<Double>) -> Double {
return interval.start + (interval.end - interval.start) * (Double(arc4random()) / Double(UInt32.max))
}
}
Usage example:
Double.random(0...300)
It is taken from RandomKit library - it looks very useful for various purposes.

One approach would be to convert the result of arc4random_uniform to double, divide the result by UInt32.max, and then multiply the result by 300.
let rand = 300 * Double(arc4random_uniform(UInt32.max)) / Double(UInt32.max)
This would produce a value between 0 and 300, inclusive. The number of possible values that you are going to get is UInt32.max.

Related

Returning exact change in SWIFT

I'm struggling with making sense of how to return the changeDue for my assignment. Trying to revise my incorrect code for class in prep for intro to programming final.
all I am trying to do is: create a method called quarters(). When I pass any double value (ChangeDue) into the method, I want to know precisely how many quarters there are as well as the partial quarter change returned.
Original code:
func getChange(Quarters: Double) -> Double {
var Change = Quarters
return Change;
}
var Quarters = 0.72;
var ChangeDue = getChange(Quarters / .25);
print(ChangeDue)
Slightly revised code which I seem to have made worse:
class changeDue {
var = quarters(.72)
func changeDue(Quarters: Double) {
var Change = Quarters
changeDue = changeDue - (quarters*.25)
}
var ChangeDue = getChange(int / .25);
print(changeDue)
}
notes/Feedback:
create a method called quarters(). When I pass any double value (ChangeDue) into the method, I want to know precisely how many quarters there are as well as the partial quarter change returned.
Create a class level variable, changeDue. This is where you will set your test input e.g. .78, 2.15.
In your method, calculate the number of quarters as the integer of changeDue/.25
Print the number of quarters.
Now you need the revised change after quarters are removed. changeDue=changeDue - (quarters*.25)
quarters = the integer of changedue/.25
changeDue is now = to the previous changeDue - (quarters times .25)
quarters(.72)
the integer of .72/.25 = 2
changedue=.72-(2 x .25) or .72 - .50 =.12
Print changeDue.
Any help would be appreciated. I've been working on this for longer than I want to admit.
Hint 1: Do not work with Double or fractional amounts. Turn dollars into pennies by multiplying everything by 100 before you start. Now you can do everything with integer arithmetic. After you get the answer, you can always divide by 100 to turn it back into dollars, if desired.
Hint 2: Do you know about the % operator? It tells you the remainder after a division.
I don't want to write your code for you (it's you who are being tested, not me, after all), but I'll just demonstrate with a different example:
51 / 7 is 7, because integer division throws away the remainder.
Sure, 7x7 is 49, with something left over. But what?
Answer: 51 % 7 is 2. Do you see?

Round a double down to one decimal place (dropping decimal places)

I want to round a double down to 1 decimal place. For example if I have a double let val = 3.1915 I want to round this down to 3.1. Normal rounding functions will round it to 3.2 but I want to basically just drop the remaining decimal places. What is the best way to do this? Is there a native function for this? I know this is pretty straight forward to do but I want to know what the best way to do this would be where I am not using any kind of workaround or bad practices. This is not a duplicate of other rounding questions because I am not asking about about rounding, I am asking how to drop decimal places.
Similarly, if the value was 3.1215, it would also round to 3.1
Use the function trunc() (which stands for truncate) which will chop away the decimal portion without rounding. Specifically, multiply the Double value by 10, truncate it, then divide by 10 again. Then, to display using 1 decimal place, use String(format:):
let aDouble = 1.15
let truncated = trunc(aDouble * 10) / 10
let string = String(format: "%.1f", truncated
print(string)
(displays "1.1")
or, to process an entire array of sample values:
let floats = stride(from: 1.099, to: 2.0, by: 0.1)
let truncs = floats
.map { trunc($0 * 10) / 10 }
.map { String(format: "%.1f", $0) }
let beforeAndAfter = zip(floats, truncs)
.map { (float: $0.0, truncString: $0.1)}
beforeAndAfter.forEach { print(String(format: "%.3f truncated to 1 place is %#", $0.0, $0.1)) }
Outputs:
1.099 truncated to 1 place is 1.0
1.199 truncated to 1 place is 1.1
1.299 truncated to 1 place is 1.2
1.399 truncated to 1 place is 1.3
1.499 truncated to 1 place is 1.4
1.599 truncated to 1 place is 1.5
1.699 truncated to 1 place is 1.6
1.799 truncated to 1 place is 1.7
1.899 truncated to 1 place is 1.8
1.999 truncated to 1 place is 1.9
By your example I assume you meant you want to Truncate, if so using multiply and casting into Int then Dividing and casting back into Float/Double will do.
Example: 3.1915 -> 3.1
var val = 3.1915
let intVal:Int = Int(val*10)
val = Float(intVal)/10.0
print(val) //3.1
If you want more decimal places simply multiply and divide by 100 or 1000 instead.
Then if for any reason you want to use the round() function there is a overloaded variant that accepts a FloatingPointRoundingRule it will work like:
var val = 3.1915
val*=10 //Determine decimal places
val.round(FloatingPoint.towardZero) // .down is also available which differs in rounding negative numbers.
val*=0.1 //This is a divide by 10
print(val) //3.1
In practical usage I'd suggest making an extension or global function instead of writing this chunk every time. It would look something like:
extension Float {
func trunc(_ decimal:Int) {
var temp = self
let multiplier = powf(10,decimal) //pow() for Double
temp = Float(Int(temp*multiplier))/multiplier //This is actually the first example put into one line
return temp
}
}
And used:
var val = 3.1915
print(val.trunc(1)) //3.1

How to compare random numbers in Swift

I’m a beginner in programming and playing around with the arc4random_uniform() function in Swift. The program I’m making so far generates a random number from 1-10 regenerated by a UIButton. However, I want the variable ’highest' that gets initialised to the random number to update if the next generated number is larger than the one currently held in it. For example the random number is 6 which is stored in highest and if the next number is 8 highest becomes 8. I don't know how to go about this. I have connected the UIButton to an IBAction function and have the following code:
var randomValue = arc4random_uniform(11) + 1
highest = Int(randomValue)
if (Int(randomValue) < highest) {
// Don’t know what to do
}
Initialise highest to 0
Every time you generate a new random number, replace the value of highest with the higher of the two numbers
highest = max(highest, randomValue)
The max() function is part of the Swift standard library and returns the larger of the two passed in vales.
edited to add
Here's a playground showing this with a bit more detail, including casting of types:
var highest: Int = 0
func random() -> Int {
let r = arc4random_uniform(10) + 1
return Int(r)
}
var randomValue = random()
highest = max(highest, randomValue)
You can see that multiple calls persist the highest value.

Swift: Double conversion inconsistency. How to correctly compare Doubles?

I have a very simple function to convert temperature from ˚C TO ˚K.
func convertKelvinToCelsius(temp:Double) ->Double {
return temp - 273.15
}
And I have a unit test to drive this function. This is where the problem is:
func testKelvinToCelsius(){
var check1 = conv.convertKelvinToCelsius(200.00) // -73.149999999999977
var check2 = 200.00 - 273.15 // -73.149999999999977
var check3 = Double(-73.15) // -73.150000000000006
//Passes
XCTAssert(conv.convertKelvinToCelsius(200.00).description == Double(-73.15).description, "Shoud convert from celsius kelvin")
//Fails
XCTAssert(conv.convertKelvinToCelsius(200.00) == Double(-73.15), "Shoud convert from celsius kelvin")
}
When you add a breakpoint and check the values of check1, check2 and check3, they are very interesting:
check1 Double -73.149999999999977
check2 Double -73.149999999999977
check3 Double -73.150000000000006
Questions:
Why does Swift return different values for check1/check2 and check3
How can I get the second test to pass, because writing it like I did the test1 smells. Why should I have to convert Doubles to Strings to be able to compare them?
Finally, when I println check1, check2 and check3, they all print to be '-73.15'. Why? Why not print accurately, and not confuse the programmers!?
To Reproduce:
Just type 200 - 273.15 == -73.15 in you playground and watch it go false!!
This is expected behavior for floating point values. They cannot be 100% accurately represented.
You can use the XCTAssertEqualWithAccuracy function to assert floating point values are within a given range of each other.
The reason println prints the same value for all is because it internally rounds them to two decimals (I assume).
This is not a Swift specific issue, this is related to the fact how decimal numbers are created in computers and what is their precision. You will need to work with DBL_EPSILON.
Swift, like most languages, uses binary floating point numbers.
With binary floating point numbers, some numbers can be represented exactly, but most can't. What can be represented exactly are integers unless they are very large (for example, 100000000000000.0 is fine), and such integers multiplied or divided by powers of two (7.375 is fine, it is 59.0 / 8, but 7.3 isn't).
Every floating point operation gives you the exact result, rounded to the nearest floating-point number. So you get
200.0 -> Exactly 200
273.15 -> A number very close to 273.15
200 - 273.15 -> A number very close to -73.15
-73.15 -> A number very close to -73.15
If you compare two numbers that are both very very close to -73.15 they are not necessarily equal. That's not a problem of the == operator; that one will determine correctly whether they are equal or not. The problem is that the two numbers can actually be different.

Division returns something different in functions

Paste the following code into a playground:
5.0 / 100
func test(anything: Float) -> Float {
return anything / 100
}
test(5.0)
The first line should return 0.05 as expected. The function test returns 0.0500000007450581. Why?
It has nothing to do with functions. Your first example is using type Double which represents floating point numbers more precisely by using 64 bits. If you were to change your second example to:
func test(anything: Double) -> Double {
return anything / 100
}
test(5.0)
You would get the result you expect. Float uses only 32 bits of data, thus it provides a less precise representation of the number. Also, floating point numbers are stored as binary values and frequently are only an approximation of the base 10 representation. That is why 0.05 is showing up as 0.0500000007450581 when stored as a Float.