Howto calculate with fractions in Objective C - objective-c

i am new to objective C and I started to learn the basics in iOS development.
How can I easily calculate with fractions in Objective C?
Example 1: 1/8000 * 60
Example 2: 1/640 / 1/400
I need to have the result (if its < 1) as a fraction, too.

I think I would implement a new class, say Fraction which has two properties, the numerator and denominator. I would then implement four (or more if necessary) of the following functions:
- (Fraction*) add:(Fraction*)operand;
- (Fraction*) subtract:(Fraction*)operand;
- (Fraction*) multiply:(Fraction*)operand;
- (Fraction*) divide:(Fraction*)operand;
- (Fraction*) invert;
+ (Fraction*) fractionByAdding:(Fraction*)op1 to:(Fraction*)op2;
+ (Fraction*) fractionBySubtracting:(Fraction*)op1 from:(Fraction*)op2;
+ (Fraction*) fractionByMultiplying:(Fraction*)op1 with:(Fraction*)op2;
+ (Fraction*) fractionByDuviding:(Fraction*)op1 by:(Fraction*)op2;
+ (Fraction*) fractionByInverting:(Fraction*)operand;
In these methods, do the usual arithmetic you learned in school. Remember to simplify if both numerator and denominator has common divisors.
EDIT: Example implementation for one of these functions:
- (Fraction*) add:(Fraction*)operand {
return [Fraction fractionByAdding:self to:operand];
}
+ (Fraction*) fractionByAdding:(Fraction*)op1 to:(Fraction*)op2 {
int num = (op1.numerator * op2.denominator) + (op2.numerator * op1.denominator);
int denom = op1.denominator * op2.denominator;
return [[Fraction alloc] initWithNumerator:num andDenominator:denom];
}
Optionally you could add a reduce or simplify method and possibly an allowReducible property and an isIrreducible method. You could also implement isEqual and compareTo methods. A description should just print "a/b" as an NSString.

You can use type cast.
int x = 1;
int y = 8000;
int z = 60;
float result = ((float)x) / y * z;

You can calculate with decimal numbers by using float variables. However, there is no direct way to get the result of the calculation as a fraction, you will always get another float, i. e. a decimal number. There are algorithms to convert decimal numbers into fractions, but it's not a language feature of Objective-C.

Related

NSDecimalNumber to the power of NSDecimalNumber

I have two NSDecimalNumbers and I need to apply one to the power of the other, originally this code was using doubles and I could compute this with the pow() function like this:
double result = pow(value1, value2);
The problem I have is I am converting the code to use NSDecimalNumbers and although they include the method toThePowerOf, it only accepts int values. At the moment the only solution I have to this problem is to convert the NSDecimalNumbers Temporarily but this results in a loss of precision.
double value1 = [decimal1 doubleValue];
double value2 = [decimal2 doubleValue];
double result = pow(value1, value2);
NSDecimalNumber *decimalResult = [[NSDecimalNumber alloc] initWithDouble:result];
Is there a way I can do this computation with NSDecimalNumbers and not lose the precision?
I need this to work with non integer values for example:
value1 = 1.06
value2 = 0.0277777777
As Joe points out, if you want to do this for positive integer powers, you can use NSDecimalPower() on an NSDecimal struct derived from your NSDecimalNumber (I personally prefer working with the structs, for performance reasons).
For the more general case of working with negative integers and fractional values, I have some code that I've modified from Dave DeLong's DDMathParser library. He has since removed the NSDecimal portion of this library, but you can find the last commit for this support. I extended Dave's exponential support into the following function:
extern NSDecimal DDDecimalPower(NSDecimal d, NSDecimal power) {
NSDecimal r = DDDecimalOne();
NSDecimal zero = DDDecimalZero();
NSComparisonResult compareToZero = NSDecimalCompare(&zero, &power);
if (compareToZero == NSOrderedSame) {
return r;
}
if (DDDecimalIsInteger(power))
{
if (compareToZero == NSOrderedAscending)
{
// we can only use the NSDecimal function for positive integers
NSUInteger p = DDUIntegerFromDecimal(power);
NSDecimalPower(&r, &d, p, NSRoundBankers);
}
else
{
// For negative integers, we can take the inverse of the positive root
NSUInteger p = DDUIntegerFromDecimal(power);
p = -p;
NSDecimalPower(&r, &d, p, NSRoundBankers);
r = DDDecimalInverse(r);
}
} else {
// Check whether this is the inverse of an integer
NSDecimal inversePower = DDDecimalInverse(power);
NSDecimalRound(&inversePower, &inversePower, 34, NSRoundBankers); // Round to 34 digits to deal with cases like 1/3
if (DDDecimalIsInteger(inversePower))
{
r = DDDecimalNthRoot(d, inversePower);
}
else
{
double base = DDDoubleFromDecimal(d);
double p = DDDoubleFromDecimal(power);
double result = pow(base, p);
r = DDDecimalFromDouble(result);
}
}
return r;
}
This runs exact calculations on positive integer powers, negative integer powers, and fractional powers that map directly to roots. It still falls back on floating point calculations for fractional powers that don't cleanly fall into one of those bins, though.
Unfortunately, this requires a few of his other supporting functions to work. Therefore, I've uploaded my enhanced versions of his _DDDecimalFunctions.h and _DDDecimalFunctions.m that provide this functionality. They also include NSDecimal trigonometry, logarithm, and a few other functions. There are currently some issues with convergence on the tangent implementation, which is why I haven't finished a public post about this.
I came across the same problem recently and developed my own function to do exactly this. The function has will calculate any base to any power as long as it yields a real answer if it determines a real answer cannot be calculated it returns NSDecimalnumber.notANumber
I have posted my solution as an answer to the same question that I posted so here is the link.

Generate Random Numbers Between Two Numbers in Objective-C

I have two text boxes and user can input 2 positive integers (Using Objective-C). The goal is to return a random value between the two numbers.
I've used "man arc4random" and still can't quite wrap my head around it. I've came up with some code but it's buggy.
float lowerBound = lowerBoundNumber.text.floatValue;
float upperBound = upperBoundNumber.text.floatValue;
float rndValue;
//if lower bound is lowerbound < higherbound else switch the two around before randomizing.
if(lowerBound < upperBound)
{
rndValue = (((float)arc4random()/0x100000000)*((upperBound-lowerBound)+lowerBound));
}
else
{
rndValue = (((float)arc4random()/0x100000000)*((lowerBound-upperBound)+upperBound));
}
Right now if I put in the values 0 and 3 it seems to work just fine. However if I use the numbers 10 and 15 I can still get values as low as 1.0000000 or 2.000000 for "rndValue".
Do I need to elaborate my algorithm or do I need to change the way I use arc4random?
You could simply use integer values like this:
int lowerBound = ...
int upperBound = ...
int rndValue = lowerBound + arc4random() % (upperBound - lowerBound);
Or if you mean you want to include float number between lowerBound and upperBound? If so please refer to this question: https://stackoverflow.com/a/4579457/1265516
The following code include the minimum AND MAXIMUM value as the random output number:
- (NSInteger)randomNumberBetween:(NSInteger)min maxNumber:(NSInteger)max
{
return min + arc4random_uniform((uint32_t)(max - min + 1));
}
Update:
I edited the answer by replacing arc4random() % upper_bound with arc4random_uniform(upper_bound) as #rmaddy suggested.
And here is the reference of arc4random_uniform for the details.
Update2:
I updated the answer by inserting a cast to uint32_t in arc4random_uniform() as #bicycle indicated.
-(int) generateRandomNumberWithlowerBound:(int)lowerBound
upperBound:(int)upperBound
{
int rndValue = lowerBound + arc4random() % (upperBound - lowerBound);
return rndValue;
}
You should avoid clamping values with mod (%) if you can, because even if the pseudo-random number generator you're using (like arc4random) is good at providing uniformly distributed numbers in its full range, it may not provide uniformly distributed numbers within the restricted modulo range.
You also don't need to use a literal like 0x100000000 because there is a convenient constant available in stdint.h:
(float)arc4random() / UINT32_MAX
That will give you a random float in the interval [0,1]. Note that arc4random returns an integer in the interval [0, 2**32 - 1].
To move this into the interval you want, you just add your minimum value and multiply the random float by the size of your range:
lowerBound + ((float)arc4random() / UINT32_MAX) * (upperBound - lowerBound);
In the code you posted you're multiplying the random float by the whole mess (lowerBound + (upperBound - lowerBound)), which is actually just equal to upperBound. And that's why you're still getting results less than your intended lower bound.
Objective-C Function:
-(int)getRandomNumberBetween:(int)from to:(int)to
{
return (int)from + arc4random() % (to-from+1);
}
Swift:
func getRandomNumberBetween(_ from: Int, to: Int) -> Int
{
return Int(from) + arc4random() % (to - from + 1)
}
Call it anywhere by:
int OTP = [self getRandomNumberBetween:10 to:99];
NSLog(#"OTP IS %ld",(long)OTP);
NSLog(#"OTP IS %#",[NSString stringWithFormat #"%ld",(long)OTP]);
For Swift:
var OTP: Int = getRandomNumberBetween(10, to: 99)
In Swift:
let otp = Int(arc4random_uniform(6))
Try this.

Simulate "Newton's law of universal gravitation" using Box2D

I want to simulate Newton's law of universal gravitation using Box2D.
I went through the manual but couldn't find a way to do this.
Basically what I want to do is place several objects in space (zero gravity) and simulate the movement.
Any tips?
It's pretty easy to implement:
for ( int i = 0; i < numBodies; i++ ) {
b2Body* bi = bodies[i];
b2Vec2 pi = bi->GetWorldCenter();
float mi = bi->GetMass();
for ( int k = i; k < numBodies; k++ ) {
b2Body* bk = bodies[k];
b2Vec2 pk = bk->GetWorldCenter();
float mk = bk->GetMass();
b2Vec2 delta = pk - pi;
float r = delta.Length();
float force = G * mi * mk / (r*r);
delta.Normalize();
bi->ApplyForce( force * delta, pi );
bk->ApplyForce( -force * delta, pk );
}
}
Unfortunately, Box2D doesn't have native support for it, but you can implement it yourself: Box2D and radial gravity code
As said by others, Box2D has no buildin support for it. But you can add support for it to the library in b2_islands.cpp. Just replace
v += h * b->m_invMass * (b->m_gravityScale * b->m_mass * gravity + b->m_force);
with
int planet_x = 0;
int planet_y = 0;
b2Vec2 gravityVector = (b2Vec2(planet_x, planet_y) - b->GetPosition());
gravityVector.Normalize();
gravityVector.x = gravityVector.x * 10.0f;
gravityVector.y = gravityVector.y * 10.0f;
v += h * b->m_invMass * (b->m_gravityScale * b->m_mass * gravityVector + b->m_force);
Thats a simple solution if you have only one planet.
If you want less force the further away you are, you could use 1/gravityVector instead of normalizing it. That would also make it possible to add up the gravity
of to planets. The you could also iterate over a planet list and sum the gravityVectors up.
Additionally implementing a function like b2World::CreatePlanet might be usefull then.
The 10.0f are just an approximation of the 9.81f from earth, you might need to adjust it. If the mass of the planet is relevant you might need a constant to be multiplied with it, to make it look more realistic, or just increase the density of the object to make it match the real weight of a planet.
Sure you can also set the gravity to 0, 0 and then calculate it before each step for every object, but that might not have so much performance.

Rounding with significant digits

In Xcode /Objective-C for the iPhone.
I have a float with the value 0.00004876544. How would I get it to display to two decimal places after the first significant number?
For example, 0.00004876544 would read 0.000049.
I didn't run this through a compiler to double-check it, but here's the basic jist of the algorithm (converted from the answer to this question):
-(float) round:(float)num toSignificantFigures:(int)n {
if(num == 0) {
return 0;
}
double d = ceil(log10(num < 0 ? -num: num));
int power = n - (int) d;
double magnitude = pow(10, power);
long shifted = round(num*magnitude);
return shifted/magnitude;
}
The important thing to remember is that Objective-C is a superset of C, so anything that is valid in C is also valid in Objective-C. This method uses C functions defined in math.h.

Convert methods from Java-actionscript to ObjectiveC

I'm tring to convert the following 3 methods from java-actionscript to Objective C.
Part of my confusion I think is not knowing what Number types, primitives I should be using. ie in actionscript you have only Number, int, and uint. These are the 3 functions I am trying to convert
public function normalize(value:Number, minimum:Number, maximum:Number):Number
{
return (value - minimum) / (maximum - minimum);
}
public function interpolate(normValue:Number, minimum:Number, maximum:Number):Number
{
return minimum + (maximum - minimum) * normValue;
}
public function map(value:Number, min1:Number, max1:Number, min2:Number, max2:Number):Number
{
return interpolate( normalize(value, min1, max1), min2, max2);
}
This is what I have so far
-(float) normalize:(float*)value
withMinimumValue:(float*)minimum
withMaximumValue:(float*)maximum
{
return (value - minimum) / (maximum - minimum);
}
-(float) interpolate:(float*)normValue
withMinimumValue:(float*)minimum
withMaximumValue:(float*)maximum
{
return minimum + (maximum - minimum) * normValue;
}
-(float) map:(float*)value
withMinimumValue1:(float*)min1
withMaximumValue1:(float*)max1
withMinimumValue2:(float*)min2
withMaximumValue2:(float*)max2
{
return interpolate( normalize(value, min1, max1), min2, max2);
}
If you're looking for a primitive type (not an object) that can handle non-integer values, float is probably fine (or CGFloat, as suggested by Chris)
unless your functions need to modify their arguments, you want the arguments to be just float not float *.
you are mixing up Objective-C message passing and plain C function invocation syntax: your example declares them as instance methods, but you're calling them like a function (won't work).
To match your declarations, the invocation would look something like:
return [self interpolate:
[self normalize:value withMinimumValue:min1 withMaximumValue:max1]
withMinimumValue:min2
withMaximumValue:max2];
Because your interpolate, normalize, and map methods do not rely on any variables from the current object instance, they might be better off as objective-C class methods (or even as plain C functions).
Given that none of your methods require any other state to work, all are basic math kinda stuff, and all are pretty straightforward, I would skip Objective-C entirely and just go with straight C. Something like:
static inline float normalize(float val, float min, float max) {
return (val - min) / (max - min);
}
Stick that in a header file somewhere in your project and be done with it. Do the same for interpolate and map.
Note: as others have mentioned, you might want to change the type to CGFloat, if needed.
Assuming you're using Apple's frameworks, these are the conversions you'll probably want to use:
Number =~ CGFloat
int =~ NSInteger
uint =~ NSUInteger