Get randomFloat Fails - ios

Why does my method return values < 0.4 in some cases?
e.g. 0.225501
#define ARC4RANDOM_MAX 0x100000000
float myVar = [self randomFloat:0.4 to:2];
- (float)randomFloat:(int)from to:(int)to
{
return ((double)arc4random() / ARC4RANDOM_MAX) * (to - from) + from;
}

You are casting your parameters to integers (which in your case changes your range to between 0 and 2), change the parameters to be float.
- (float)randomFloat:(float)from to:(float)to

when dividing and using floats the precision of the decimals is sometimes lost. Maybe you can use a long with N fixed number of digits and place the decimal point before those digits. The other day I was getting strange results when adding (1 + (3/10))= should be 1.3 but I always had something like 1.29995 . Hope it helps

Related

Algorithm to always sum sliders to 100% failing due to zeroes

This is (supposed to be) a function which makes sure that the the sum of a number of slider's values always adds up to globalTotal.
A slider value can be changed manually by the user to changer.value and then when applying this function to the values of the other sliders, it can determine their new or endVal.
It takes the startVal of the slider which needs changing and the original value of the slider that changed changerStartVal and can determine the new value others by weighting.
The problem and my question is. Sometimes remainingStartVals can be zero (when the slider changing gets moved all the way to maximum) or startVal can be zero (when the slider changing is moved to zero and then another slider is moved). When this happens I get a divide-by-zero or a multiply-by-zero respectively. Both of which are bad and lead to incorrect results. Is there an easy way to fix this?
func calcNewVal(startVal: Float, changerStartVal: Float) -> Float {
let remainingStartVals = globalTotal - changerStartVal
let remainingNewVals = globalTotal - changer.value
let endVal = ((startVal * (100 / remainingStartVals)) / 100) * remainingNewVals
return endVal
}
This is a mathematical problem, not a problem related to Swift or any specific programming language so I'll answer with mathematical formulas and explanations rather than code snippets.
I don't really understand your algorithm either. For example in this line:
let endVal = ((startVal * (100 / remainingStartVals)) / 100) * remainingNewVals
you first multiply by 100 and then divide by 100, so you could just leave all these 100 factors out in the first place!
However, I think I understand what you're trying to achieve and the problem is that there is no generic solution. Before writing an algorithm you have to define exactly how you want it to behave, including all edge cases.
Let's define:
vi as the value of the i-th slider and
Δi as the change of the i-th slider's value
Then you have to think of the following cases:
Case 1:
0 < vi ≤ 1 for all sliders (other than the one you changed)
This is probably the common case you were thinking about. In this case you want to adjust the values of your unchanged sliders so that their total change is equal to the change Δchanged of the slider you changed. In other words:
∑i Δi = 0
If you have 3 sliders this reduces to:
Δ1 + Δ2 + Δ3 = 0
And if the slider that changed is the one with i = 1 then this requirement would read:
Δ1 = – (Δ2 + Δ3)
You want the sliders to adjust proportionally which means that this change Δ1 should not be distributed equally on the other sliders but depending on their current value:
Δ2 = – w2 * Δ1
Δ3 = – w3 * Δ1
The normed weight factors are
w2 = v2 / (v2 + v3)
w3 = v3 / (v2 + v3)
Thus we get:
Δ2 = – v2 / (v2 + v3) * Δ1
Δ3 = – v3 / (v2 + v3) * Δ1
So these are the formulas to applied for this particular case.
However, there are quite a few other cases that don't work with this approach:
Case 2:
vi = 0 for at least one, but not all of the sliders (other than the one you changed)
In this case the approach from case 1 would still work (plus it would be the logical thing to do). However, a slider's value would never change if it's zero. All of the change will be distributed over the sliders with a value > 0.
Case 3:
vi = 0 for all sliders (other than the one you changed)
In this case the proportional change doesn't work because there is simply no information how to distribute the change over the sliders. They're all zero! This is actually your zero division problem: In the case where we have 3 sliders and the slider 1 changes we'll get
v2 + v3 = 0
This is only another manifestation of the fact that the weight factors wi are simply undefined. Thus, you'll have to manually define what will happen in this case.
The most plausible thing to do in this case is to distribute the change evenly over all sliders:
Δi = – (1 / n) * Δ1
where n is the number of sliders (excluding the one that was changed!). With this logic, every slider gets "the same share" of the change.
Now that we're clear with our algorithm you can implement these cases in code. Here some pseudo code as an example:
if sum(valuesOfAllSlidersOtherThanTheSliderThatChanged) == 0 {
for allUnchangedSliders {
// distribute change evenly over the sliders
Δi = – (1 / n) * Δ_changedSlider
}
}
else {
for allUnchangedSliders {
// use weight factor to change proportionally
Δi = – v_i / ∑(v_i) * Δ_changedSlider
}
}
Please be aware that you must cache the values of the current state of your sliders at the beginning or (even better) first compute all the changes and then apply all the changes in a batch. Otherwise you will use a value v2' that you just computed for determining the value v3' which will obviously result in incorrect values.
Hey #Sean the simplest adjustment that I could think of here is to check if the remainingStartVals is not 0 that means that there are weights assigned to the other sliders and also check if a single slider had a weight to begin with which means its startVal shouldn't be equal to 0
func calcNewVal(startVal: Float, changerStartVal: Float) -> Float{
var endVal = 0
let remainingStartVals = globalTotal - changerStartVal
if remainingStartVals != 0 || startVal != 0{
let remainingNewVals = globalTotal - changer.value
endVal = ((startVal * (100 / remainingStartVals)) / 100) * remainingNewVals
}
return endVal
}

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 don't these numbers add in Xcode Debugger?

I'm using the Xcode debugger, and these numbers don't seem to add. I was curious as to why :
(lldb) p height
(CGFloat) $R0 = 2.1815627849240522E-314
(lldb) p frame.size
(CGSize) $R1 = (width = 375, height = 1000)
(lldb) p frame.size.height
(CGFloat) $R2 = 1000
(lldb) p height + frame.size.height
(CGFloat) $R3 = 1000
I have 3 questions about this..
What is 2.1815627849240522E-314 ? What kind of number is that?
Is it possible to instantiate temporary variables in debugger like you would in Ruby console, Chrome console etc.? For example, let temp_x = 4 ?
Why does my $R3 return 1000 and not.. something bigger?
2.1815627849240522E-314 is essentially zero. 1000 + 0 = 1000.
Floating point numbers have two parts - mantissa and exponent (position of the decimal point). e-341 means "move the decimal point 341 places to the right"
Adding 1000 to that very very small number creates a number that would be equal
1000.000...(> 300 zeros here)...2181567849240522
Even double mantissa can't represent numbers like this (double can represent up to 17 decimal digits) so it takes only the more important numbers in the beginning.
I encourage you to read through What Every Programmer Should Know About Floating-Point Arithmetic

Evaluation (NSIntegers) inside if-statement Objective-C

I am in doubt, why this work correctly:
NSInteger row = indexPath.row;
NSInteger preloadTrigger = self.nodes.count - 20;
if (row >= preloadTrigger) {
[self.loader loadNextposts];
}
And this does not (just skips the if-statement):
if (indexPath.row >= self.nodes.count - 20) {
[self.loader loadNextposts];
}
when the value of self.nodes.count - 20 is negative.
However, when the value of the expression is positive, it works fine always.
A very strange behavior, as I cannot see semantic difference in two expressions.
Update:
So, I decided to test it:
(lldb) po self.nodes.count - 20
18446744073709551601
(lldb) po preloadTrigger
-15
According to Apple Docs, count property is a NSUIntegerin objective-C.
When you write :
NSInteger preloadTrigger = self.nodes.count - 20;
In fact you are casting count to a NSInteger object, and can have a negative value if count isn't greater than 20.
But when you write :
(indexPath.row >= self.nodes.count - 20)
count is a NSUInteger object, and subtract 20 from it will always lead to a positive number (a huge one by the way).
Because nodes.count is NSUInteger and row is NSInteger. Unsigned integer - 20 is never a negative value, but results a huge positive value where you expect it to be negative.
I'll add some explanation to the other, correct answers.
So, here is how it goes:
self.nodes.count is of type NSUInteger, which is the same as unsigned long int in 64 bit systems, or alternatively unsigned int in 32 bit systems.
The literal 20 is of type int.
When you form the expression self.nodes.count - 20, 20 is 'promoted' to the unsigned integer type of the other operand (self.nodes.count), because it has the wider range of the two.
That is because, when both operands have types of different sizes, the smaller one gets promoted to the larger one to make them equal and calculate the result in those terms (in hardware, arithmetical operations between values of different types aren't really defined - the bit representations differ).
The problem is that, in exchange for being able to represent a wider range of positive values with the same bit length, unsigned integers can not represent negative values. So, when 20 is greater than self.nodes.count, the result "wraps around" to a large, unsigned integer.
On the other hand indexPath.row, too, is an unsigned integer (NSUInteger), so you end up comparing the relatively small row value with the huge result of the subtraction operation; the test:
if (indexPath.row >= self.nodes.count - 20)
...always fails (the left side is smaller).
If you first cast both results to signed integer and then compare those signed integers:
NSInteger row = indexPath.row;
NSInteger preloadTrigger = self.nodes.count - 20;
if (row >= preloadTrigger) {
...then no wrapping/underflow occurs and you get the expected result.

Rounding to specific value?

I need to round a number, let's say 543 to either the hundreds or the tens place. It could be either one, as it's part of a game and this stage can ask you to do one or the other.
So for example, it could ask, "Round number to nearest tens", and if the number was 543, they would have to enter in 540.
However, I don't see a function that you can specify target place value to round at. I know there's an easy solution, I just can't think of one right now.
From what I see, the round function rounds the last decimal place?
Thanks
To rounding to 100's place
NSInteger num=543;
NSInteger deci=num%100;//43
if(deci>49){
num=num-deci+100;//543-43+100 =600
}
else{
num=num-deci;//543-43=500
}
To round to 10's place
NSInteger num=543;
NSInteger deci=num%10;//3
if(deci>4){
num=num-deci+100;//543-3+10 =550
}
else{
num=num-deci;//543-3=540
}
EDIT:
Tried to merge the above in one:
NSInteger num=543;
NSInteger place=100; //rounding factor, 10 or 100 or even more.
NSInteger condition=place/2;
NSInteger deci=num%place;//43
if(deci>=condition){
num=num-deci+place;//543-43+100 =600.
}
else{
num=num-deci;//543-43=500
}
You may just use an algorithm in your code:
For example, lets say that you need to round up a number to hundred's place.
int c = 543
int k = c % 100
if k > 50
c = (c - k) + 100
else
c = c - k
To round numbers, you can use the modulus operator, %.
The modulus operator gives you the remainder after division.
So 543 % 10 = 3, and 543 % 100 = 43.
Example:
int place = 10;
int numToRound=543;
// Remainder is 3
int remainder = numToRound%place;
if(remainder>(place/2)) {
// Called if remainder is greater than 5. In this case, it is 3, so this line won't be called.
// Subtract the remainder, and round up by 10.
numToRound=(numToRound-remainder)+place;
}
else {
// Called if remainder is less than 5. In this case, 3 < 5, so it will be called.
// Subtract the remainder, leaving 540
numToRound=(numToRound-remainder);
}
// numToRound will output as 540
NSLog(#"%i", numToRound);
Edit: My original answer was submitted before it was ready, because I accidentally hit a key to submit it. Oops.

Resources