Swift get Fraction of Float - objective-c

I've been trying out swift lately and i've come across a rather simple Problem.
In Obj-C when i want to get the fraction digits of a float i'd do the following:
float x = 3.141516
int integer_x = (int)x;
float fractional_x = x-integer_x;
//Result: fractional_x = 0.141516
in Swift:
let x:Float = 3.141516
let integerX:Int = Int(x)
let fractionalX:Float = x - integerX
-> this results in an error because of mismachting types
Any Idea how to do it correctly?
Thanks in Advance
Malte

Use the modf function:
let v = 3.141516
var integer = 0.0
let fraction = modf(v, &integer)
println("fraction: \(fraction)");
output:
fraction: 0.141516
For float instead of double just use: modff

Use .truncatingRemainder(dividingBy:) which replaced the modulo operator (x % 1), which (for modulo)
immediately (it is only one character), and
with few cpu cycles (presumably only one cycle, since modulo is a common cpu instruction)
gives the fractional part.
let x:Float = 3.141516
let fracPart = x.truncatingRemainder(dividingBy: 1) // fracPart is now 0.141516
fracPart will assume the value: 0.141516. This works for double and float.

The problem is that you cannot subtract Float and Int, you should convert one of this value to be the same as another, try that:
let fractionalX:Float = x - Float(integerX)

Swift 3 does not like the modulus operator %. It wants me to use truncatingRemainder of Double type.
let x1:Double = 123.00
let t1 = x1.truncatingRemainder(dividingBy: 1)
print("t1 = \(t1)")
let x2:Double = 123.45
let t2 = x2.truncatingRemainder(dividingBy: 1)
print("t2 = \(t2)")
Produces output:
t1 = 0.0
t2 = 0.450000000000003
To remove the 3 quadrillionth artifact you should probably round the result.

Why using an int whatsoever?
What about this instead:
import Darwin
let x = 3.1415926
let xf = x - (x > 0 ? floor(x) : ceil(x))
It will use doubles by default here. Feel free to use floats if it's what you need:
let x: Float = 3.1415926
Is that what you are looking for?

Related

How to handle integer overflow in OCaml when converting from float using int_of_float?

OCaml newbie here.
I am trying to figure out how to deal with integer overflow in OCaml when converting from float to int.
I was hoping to use try ... with ... or compare it to nan (since at actually has to return nan when float is too large?), but looks like it does not throw any errors.
And even more surprisingly for very large floats int_of_float simply returns 0.
utop # 0 = int_of_float 9999999999999999999.0;;
- : bool = true
utop # int_of_float 9999999999999999999.0;;
- : int = 0
How do I handle float to int conversion properly? (and more generally int overflow?)
Indeed, OCaml's manual indicates that float_of_int's "result is unspecified if the argument is nan or falls outside the range of representable integers."
A possibility is to check beforehand whether your float will fit or not, and return an option or raise an exception, as in e.g.
let safe_int_of_float f =
if classify_float f = FP_nan then None
else if f >= float_of_int max_int then None
else if f <= float_of_int min_int then None
else Some (int_of_float f)
The following module will do the job.
(*
This module defines the range of integers that can be represented
interchangeably with the float or with int type.
Note that this range depends on size of the int type, which depends
on the compilation target.
*)
(*
OCaml ints have 31 bits or 63 bits.
OCaml floats are double-precision floats (IEEE-754 binary64).
*)
let int_range_min_float = max (-.2.**53.) (float min_int)
let int_range_max_float = min (2.**53.) (float max_int)
let exact_int_of_float x =
if x >= int_range_min_float && x <= int_range_max_float then
truncate x
else
invalid_arg "exact_int_of_float: out of range"
let int_range_min_int = exact_int_of_float int_range_min_float
let int_range_max_int = exact_int_of_float int_range_max_float
let exact_float_of_int x =
if x >= int_range_min_int && x <= int_range_max_int then
float x
else
invalid_arg "exact_float_of_int: out of range"
let test () =
let imin, imax = int_range_min_int, int_range_max_int in
let fmin, fmax = int_range_min_float, int_range_max_float in
assert (exact_int_of_float 1. = 1);
assert (exact_int_of_float (-1.) = -1);
assert (fmin < 0.);
assert (fmax > 0.);
assert (imin < 0);
assert (imax > 0);
assert (float (truncate fmin) = fmin);
assert (float (truncate fmax) = fmax);
assert (truncate (float imin) = imin);
assert (truncate (float imax) = imax);
assert (float (imin + 1) = float imin +. 1.);
assert (float (imin + 2) = float imin +. 2.);
assert (float (imax - 1) = float imax -. 1.);
assert (float (imax - 2) = float imax -. 2.)

Rounding a float number in objective-c

I want to know if there is a simple function that I can use such this sample.
I have a
float value = 1.12345;
I want to round it with calling something like
float value2 = [roundFloat value:value decimal:3];
NSLog(#"value2 = %f", value2);
And I get "1.123"
Is there any Library or default function for that or I should write a code block for this type of calculations?
thank for your help in advance
Using NSLog(#"%f", theFloat) always outputs six decimals, for example:
float theFloat = 1;
NSLog(#"%f",theFloat);
Output:
1.000000
In other words, you will never get 1.123 by using NSLog(#"%f", theFloat).
Cut-off after three decimals:
float theFloat = 1.23456;
float newFLoat = (int)(theFloat * 1000.0) / 1000.0;
NSLog(#"%f",newFLoat);
Output:
1.234000
Round to three decimals (using roundf() / lroundf() / ceil() / floor()):
float theFloat = 1.23456;
float newFLoat = (int)(roundf(theFloat * 1000.0)) / 1000.0;
NSLog(#"%f",newFLoat);
Output:
1.235000
Round to three decimals (dirty way):
float theFloat = 1.23456;
NSString *theString = [NSString stringWithFormat:#"%.3f", theFloat];
float newFloat = [theString floatValue];
NSLog(#"%#",theString);
NSLog(#"%f",newFloat);
Output:
1.235
1.235000
For printing the value use:
NSLog(#"value2 = %.3f", value2);
Rounding to 3 decimal digits before calculations doesn't really make sense because float is not a precise number. Even if you round it to 1.123, it will be something like 1.122999999998.
Rules:
Usually you round up only to print the result - string formatter can handle it (see above).
For precise calculations (e.g. currency), don't use floating point, use NSDecimalNumber or fixed point arithmetics.
Floating point numbers don't have decimal places, they have binary places. Decimal-radix numbers have decimal places. You can't round floating point numbers to specific numbers of decimal places unless you convert to a decimal radix. No routine, method, function etc., that returns a floating point value can possibly carry out this task.
Note that "Round" is not necessarily as simple a topic as you think. For example
DIY Calculator: Rounding Algorithms 101 lists 16 different methods for rounding a number.
Wikipedia:Rounding covers a lot of the same ground
And Cplusplus has source code for a bunch of Rounding Algorithms that are easy translatable to objective-c
How you want to round will depend on the context of what you are doing with for data.
And I should point out that Stack Overflow already has a plethora of other questions about rounding in objective-c
//Your Number to Round (can be predefined or whatever you need it to be)
float numberToRound = 1.12345;
float min = ([ [[NSString alloc]initWithFormat:#"%.0f",numberToRound] floatValue]);
float max = min + 1;
float maxdif = max - numberToRound;
if (maxdif > .5) {
numberToRound = min;
}else{
numberToRound = max;
}
//numberToRound will now equal it's closest whole number (in this case, it's 1)
Here is a simple way to do it:
float numberToRound = 1.12345f;
float remainder = numberToRound*1000.0f - (float)((int)(numberToRound*1000.0f));
if (remainder >= 0.5f) {
numberToRound = (float)((int)(numberToRound*1000.0f) + 1)/1000.0f;
}
else {
numberToRound = (float)((int)(numberToRound*1000.0f))/1000.0f;
}
For an arbitrary decimal place, substitute 1000.0f in the above code with
float mult = powf(10.0f, decimal);
try
#import <math.h>
float cutFloat( float number, int decimal) {
number = number*( pow(10,decimal) );
number = (int)number;
number = number/( pow(10,decimal) ) ;
return number;
}

Randomize float using arc4random?

I have a float and I am trying to get a random number between 1.5 - 2. I have seen tutorials on the web but all of them are doing the randomization for 0 to a number instead of 1.5 in my case. I know it is possible but I have been scratching my head on how to actually accomplish this. Can anyone help me?
Edit1: I found the following method on the web but I do not want all these decimals places. I only want things like 5.2 or 7.4 etc...
How would I adjust this method to do that?
-(float)randomFloatBetween:(float)num1 andLargerFloat:(float)num2
{
int startVal = num1*10000;
int endVal = num2*10000;
int randomValue = startVal + (arc4random() % (endVal - startVal));
float a = randomValue;
return (a / 10000.0);
}
Edit2: Ok so now my method is like this:
-(float)randomFloatBetween:(float)num1 andLargerFloat:(float)num2
{
float range = num2 - num1;
float val = ((float)arc4random() / ARC4RANDOM_MAX) * range + num1;
return val;
}
Will this produce numbers like 1.624566 etc..? Because I only want say 1.5,1.6,1.7,1.8,1.9, and 2.0.
You can just produce a random float from 0 to 0.5 and add 1.5.
EDIT:
You're on the right track. I would use the maximum random value possible as your divisor in order to get the smallest intervals you can between possible values, rather than this arbitrary division by 10,000 thing you have going on. So, define the maximum value of arc4random() as a macro (I just found this online):
#define ARC4RANDOM_MAX 0x100000000
Then to get a value between 1.5 and 2.0:
float range = num2 - num1;
float val = ((float)arc4random() / ARC4RANDOM_MAX) * range + num1;
return val;
This will also give you double precision if you want it (just replace float with double.)
EDIT AGAIN:
Yes, of course this will give you values with more than one decimal place. If you want only one, just produce a random integer from 15 to 20 and divide by 10. Or you could just hack off the extra places afterward:
float range = num2 - num1;
float val = ((float)arc4random() / ARC4RANDOM_MAX) * range + num1;
int val1 = val * 10;
float val2= (float)val1 / 10.0f;
return val2;
arc4random is a 32-bit generator. It generates Uint32's. The maximum value of arc4random() is UINT_MAX. (Do not use ULONG_MAX!)
The simplest way to do this is:
// Generates a random float between 0 and 1
inline float randFloat()
{
return (float)arc4random() / UINT_MAX ;
}
// Generates a random float between imin and imax
inline float randFloat( float imin, float imax )
{
return imin + (imax-imin)*randFloat() ;
}
// between low and (high-1)
inline float randInt( int low, int high )
{
return low + arc4random() % (high-low) ; // Do not talk to me
// about "modulo bias" unless you're writing a casino generator
// or if the "range" between high and low is around 1 million.
}
This should work for you:
float mon_rand() {
const u_int32_t r = arc4random();
const double Min = 1.5;
if (0 != r) {
const double rUInt32Max = 1.0 / UINT32_MAX;
const double dr = (double)r;
/* 0...1 */
const double nr = dr * rUInt32Max;
/* 0...0.5 */
const double h = nr * 0.5;
const double result = Min + h;
return (float)result;
}
else {
return (float)Min;
}
}
That was the simplest I could think of, when I had the same "problem" and it worked for me:
// For values from 0.0 to 1.0
float n;
n = (float)((arc4random() % 11) * 0.1);
And in your case, from 1.5 to 2.0:
float n;
n = (float)((arc4random() % 6) * 0.1);
n += 15 * 0.1;
For anybody who wants more digits:
If you just want float, instead of arc4random(3) it would be easier if you use rand48(3):
// Seed (only once)
srand48(arc4random()); // or time(NULL) as seed
double x = drand48();
The drand48() and erand48() functions return non-negative, double-precision, floating-point values, uniformly distributed over the interval [0.0 , 1.0].
Taken from this answer.

Rounding an Objective-C float to the nearest .05

I want to round the following floating point numbers to the nearest 0.05.
449.263824 --> 449.25
390.928070 --> 390.90
390.878082 --> 390.85
How can I accomplish that?
The match the output in your question, you can do the following:
float customRounding(float value) {
const float roundingValue = 0.05;
int mulitpler = floor(value / roundingValue);
return mulitpler * roundingValue;
}
Example:
NSLog(#"Output: %f --> %.2f", 449.263824, customRounding(449.263824));
There's the round() function. I think you need to do this:
double rounded = round(number * 20.0) / 20.0;
As with all floating point operations, since 1/5 is not directly representable as a binary value, you'll see bizarre not quite exact results. If you don't like that, you can use NSDecimalNumber's -decimalNumberByRoundingAccordingToBehaviour: method but it'll be a bit slower.
I know the question is answered but I used the following code:
float unrounded = 2.234;
float decimal = 0.05;
float decimal2 = 1/decimal;
float rounded = (((int)((unrounded*decimal2)+0.5))/decimal2);
For example:
> unrounded = 2.234
> decimal = 0.05
> decimal2 = 1/0.05 = 20
>
> rounded:
> 2.234 * 20 = 44.68
> 44.68 + 0.5 = 45.18
> make an integer: 45
> 45 / 20 = 2.25
You could use an NSNumberFormatter to carry out rounding and indeed to specify the rounding you require via one of the NSNumberFormatterRoundingMode options. (Search for "NSNumberFormatterRoundingMode" in the above class reference to see the defaults.)
However, as #Jesse states in the comment on your question, there doesn't seems to be any standard form of rounding going on in the examples you're provided.
If it were round to the nearest x, then you could go with:
roundedValue = originalValue + x * 0.5;
roundedValue -= fmodf(roundedValue, x);
As it is, it isn't entirely clear what you want.
Use floor:
#include <math.h>
...
double result = floor(number * 20.0) / 20.0;

How to create a random float in Objective-C?

I'm trying to create a random float between 0.15 and 0.3 in Objective-C. The following code always returns 1:
int randn = (random() % 15)+15;
float pscale = (float)randn / 100;
What am I doing wrong?
Here is a function
- (float)randomFloatBetween:(float)smallNumber and:(float)bigNumber {
float diff = bigNumber - smallNumber;
return (((float) (arc4random() % ((unsigned)RAND_MAX + 1)) / RAND_MAX) * diff) + smallNumber;
}
Try this:
(float)rand() / RAND_MAX
Or to get one between 0 and 5:
float randomNum = ((float)rand() / RAND_MAX) * 5;
Several ways to do the same thing.
use arc4random() or seed your random values
try
float pscale = ((float)randn) / 100.0f;
Your code works for me, it produces a random number between 0.15 and 0.3 (provided I seed with srandom()). Have you called srandom() before the first call to random()? You will need to provide srandom() with some entropic value (a lot of people just use srandom(time(NULL))).
For more serious random number generation, have a look into arc4random, which is used for cryptographic purposes. This random number function also returns an integer type, so you will still need to cast the result to a floating point type.
Easiest.
+ (float)randomNumberBetween:(float)min maxNumber:(float)max
{
return min + arc4random_uniform(max - min + 1);
}
Using srandom() and rand() is unsafe when you need true randomizing with some float salt.
On MAC_10_7, IPHONE_4_3 and higher you can use arc4random_uniform(upper_bound)*.
It allows to generate true random integer from zero to *upper_bound*.
So you can try the following
u_int32_t upper_bound = <some big enough integer>;
float r = 0.3 * (0.5 + arc4random_uniform(upper_bound)*1.0/upper_bound/2);
To add to #Caladain's answer, if you want the solution to be as easy to use as rand(), you can define these:
#define randf() ((CGFloat)rand() / RAND_MAX)
#define randf_scaled(scale) (((CGFloat)rand() / RAND_MAX) * scale)
Feel free to replace CGFloat with double if you don't have access to CoreGraphics.
I ended up generating to integers one for the actual integer and then an integer for the decimal. Then I join them in a string then I parse it to a floatvalue with the "floatValue" function... I couldn't find a better way and this works for my intentions, hope it helps :)
int integervalue = arc4random() % 2;
int decimalvalue = arc4random() % 9;
NSString *floatString = [NSString stringWithFormat:#"%d.%d",integervalue,decimalvalue];
float randomFloat = [floatString floatValue];