How to test whether the square root of a number will be rational? - objective-c

How can you test whether the square root of a number will be rational or not?
Is this even possible?
I need this because I need to work out whether to display a number as a surd or not in a maths app I'm developing at the moment.

For integer inputs, only the square roots of the square numbers are rationals. So your problem boils down to find if your number is a square number. Compare the question: What's a good algorithm to determine if an input is a perfect square?.
If you have rational numbers as inputs (that is, a number given as the ratio between two integer numbers), check that both divisor and dividend are perfect squares.
For floating-point values, there is probably no solution because you can't check if a number is rational with the truncated decimal representation.

From wikipedia: The square root of x is rational if and only if x is a rational number that can be represented as a ratio of two perfect squares.
So you need to find a rational approxmiation for your input number. So far the only algorithm I've nailed down that does this task is written in Saturn Assembler for the HP48 series of calculators.

After reading comments and the answers to another question I have since asked, I realised that the problem came from a floating point inaccuracy which meant that some values (eg 0.01) would fail the logical test at the end of the program. I have amended it to use NSDecimalNumber variables instead.
double num, originalnum, multiplier;
int a;
NSLog(#"Enter a number");
scanf("%lf", &num);
//keep a copy of the original number
originalnum = num;
//increases the number until it is an integer, and stores the amount of times it does it in a
for (a=1; fmod(num, 1) != 0 ; a++) {
num *= 10;
}
a--;
//when square-rooted the decimal points have to be added back in
multiplier = pow(10, (a/2));
if (fmod(originalnum, 1) != 0) {
multiplier = 10;
}
NSDecimalNumber *temp = [NSDecimalNumber decimalNumberWithDecimal:[[NSNumber numberWithDouble:sqrt(num)/multiplier] decimalValue]];
NSDecimalNumber *result = [temp decimalNumberByMultiplyingBy:temp];
NSDecimalNumber *originum = [NSDecimalNumber decimalNumberWithDecimal:[[NSNumber numberWithDouble:originalnum] decimalValue]];
if ((fmod(sqrt(num), 1) == 0) && ([result isEqualToNumber:originum])) {
NSLog(#"The square root of %g is %#", originalnum, temp);
}
else {
NSLog(#"The square root of this number is irrational");
}

If you're dealing with integers, note that a positive integer has a rational square root if and only if it has an integer square root, that is, if it is a perfect square. For information on testing for that, please see this amazing StackOverflow question.

On https://math.stackexchange.com/ there is the question What rational numbers have rational square roots? that yielded an answer from Jakube that states that for "...rational numbers, an answer is to determine if the numerator and denominator are integers raised to the power of 2."
Good ways to work out whether natural numbers are perfect squares depends on the natural numbers the function supports (and the computer programming language being used) and the memory available etc. Here are a set of useful links:
https://math.stackexchange.com/questions/3431150/is-there-a-way-to-check-if-an-integer-is-a-square
https://codereview.stackexchange.com/questions/204974/fastest-way-to-determine-if-a-number-is-perfect-square
Fastest way to determine if an integer's square root is an integer
Check if BigInteger is not a perfect square
I developed and tested a solution in Java that works well enough for me with a set of natural numbers. The gist of this is given below. This code depends on BigMath and is implemented in agdt-java-math albeit in a couple of different classes:
/**
* #param x The number to return the square root of (if the result is
* rational).
* #return The square root of x if that square root is rational and
* {#code null} otherwise.
*/
public static BigRational getSqrtRational(BigRational x) {
BigInteger[] numden = getNumeratorAndDenominator(x);
BigInteger nums = getPerfectSquareRoot(numden[0]);
if (nums != null) {
BigInteger dens = getPerfectSquareRoot(numden[1]);
if (dens != null) {
return BigRational.valueOf(nums).divide(BigRational.valueOf(dens));
}
}
return null;
}
/**
* #param x The value for which the numerator and denominator are returned.
* #return The numerator and denominator of {#code x}
*/
public static BigInteger[] getNumeratorAndDenominator(BigRational x) {
BigInteger[] r = new BigInteger[2];
r[0] = x.getNumeratorBigInteger();
r[1] = x.getDenominatorBigInteger();
if (Math_BigInteger.isDivisibleBy(r[0], r[1])) {
r[0] = r[0].divide(r[1]);
r[1] = BigInteger.ONE;
}
return r;
}
/**
* #param x The number to return the square root of if that is an integer.
* #return The square root of {#code x} if it is an integer and {#code null}
* otherwise.
*/
public static BigInteger getPerfectSquareRoot(BigInteger x) {
if (x.compareTo(BigInteger.ZERO) != 1) {
return null;
}
BigInteger xs = x.sqrt();
if (x.compareTo(xs.multiply(xs)) == 0) {
return xs;
}
return null;
}
Also as square of any rational is rational, no rational is the square root of an irrational. This is clear to me having read Yves answer to: Prove that the square root of any irrational number is irrational. So, dealing with the case of rational numbers is sufficient to answer this question for all real numbers.

Related

What's the maximum absolute error for floating-point comparisons?

I want to compare floats like this:
void assertEquals(CGFloat f, CGFloat g) {
NSCAssert(fabs(f-g) < 0.1);
}
void assertLE(CGFloat f, CGFloat g) {
NSCAssert(f <= g + 0.1);
}
Is there a tighter bound I can use than 0.1? What's the maximum error that a floating-point comparison can have? Is there a macro, so that I don't hardcode the number?
The maximum rounding error in an IEEE 754 32-bit binary floating point calculation is about 1e31. I calculated it in Java using this program:
public class Test {
public static void main(String[] args) {
float biggest = Float.MAX_VALUE;
float nextBiggest = Math.nextDown(biggest);
float gap = biggest - nextBiggest;
System.out.println(gap / 2);
}
}
It is half the distance between the two biggest finite numbers. You can do a similar calculation in Objective-C for the format you are using. It will be far too big to use for reasonable magnitude calculations.
You really do need to work with relative error, either explicitly or by picking a fixed bound that is appropriate for the magnitudes of your numbers.

Return same double only if the double is an int? (no decimals) Obj-C

I'm using a for-loop to determine whether the long double is an int. I have it set up that the for loop loops another long double that is between 2 and final^1/2. Final is a loop I have set up that is basically 2 to the power of 2-10 minus 1. I am then checking if final is an integer. My question is how can I get only the final values that are integers?
My explanation may have been a bit confusing so here is my entire loop code. BTW I am using long doubles because I plan on increasing these numbers very largely.
for (long double ld = 1; ld<10; ld++) {
long double final = powl(2, ld) - 1;
//Would return e.g. 1, 3, 7, 15, 31, 63...etc.
for (long double pD = 2; pD <= powl(final, 0.5); pD++) {
//Create new long double
long double newFinal = final / pD;
//Check if new long double is int
long int intPart = (long int)newFinal;
long double newLong = newFinal - intPart;
if (newLong == 0) {
NSLog(#"Integer");
//Return only the final ints?
}
}
}
Just cast it to an int and subtract it from itself?
long double d;
//assign a value to d
int i = (int)d;
if((double)(d - i) == 0) {
//d has no fractional part
}
As a note... because of the way floating point math works in programming, this == check isn't necessarily the best thing to do. Better would be to decide on a certain level of tolerance, and check whether d was within that tolerance.
For example:
if(fabs((double)(d - i)) < 0.000001) {
//d's fractional part is close enough to 0 for your purposes
}
You can also use long long int and long double to accomplish the same thing. Just be sure you're using the right absolute value function for whatever type you're using:
fabsf(float)
fabs(double)
fabsl(long double)
EDIT... Based on clarification of the actual problem... it seems you're just trying to figure out how to return a collection from a method.
-(NSMutableArray*)yourMethodName {
NSMutableArray *retnArr = [NSMutableArray array];
for(/*some loop logic*/) {
// logic to determine if the number is an int
if(/*number is an int*/) {
[retnArr addObject:[NSNumber numberWithInt:/*current number*/]];
}
}
return retnArr;
}
Stick your logic into this method. Once you've found a number you want to return, stick it into the array using the [retnArr addObject:[NSNumber numberWithInt:]]; method I put up there.
Once you've returned the array, access the numbers like this:
[[arrReturnedFromMethod objectAtIndex:someIndex] intValue];
Optionally, you might want to throw them into the NSNumber object as different types.
You can also use:
[NSNumber numberWithDouble:]
[NSNumber numberWithLongLong:]
And there are matching getters (doubleValue,longLongValue) to extract the number. There are lots of other methods for NSNumber, but these seem the most likely you'd want to be using.

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.

NSString constrainedToSize method?

Not to get confused with the NSString sizeWithFont method that returns a CGSize, what I'm looking for is a method that returns an NSString constrained to a certain CGSize. The reason I want to do this is so that when drawing text with Core Text, I can get append an ellipses (...) to the end of the string. I know NSString's drawInRect method does this for me, but I'm using Core Text, and kCTLineBreakByTruncatingTail truncates the end of each line rather than the end of the string.
There's this method that I found that truncates a string to a certain width, and it's not that hard to change it to make it work for a CGSize, but the algorithm is unbelievably slow for long strings, and is practically unusable. (It took over 10 seconds to truncate a long string). There has to be a more "computer science"/mathematical algorithm way to do this faster. Anyone daring enough to try to come up with a faster implementation?
Edit: I've managed to make this in to a binary algorithm:
-(NSString*)getStringByTruncatingToSize:(CGSize)size string:(NSString*)string withFont:(UIFont*)font
{
int min = 0, max = string.length, mid;
while (min < max) {
mid = (min+max)/2;
NSString *currentString = [string substringWithRange:NSMakeRange(min, mid - min)];
CGSize currentSize = [currentString sizeWithFont:font constrainedToSize:CGSizeMake(size.width, MAXFLOAT)];
if (currentSize.height < size.height){
min = mid + 1;
} else if (currentSize.height > size.height) {
max = mid - 1;
} else {
break;
}
}
NSMutableString *finalString = [[string substringWithRange:NSMakeRange(0, min)] mutableCopy];
if(finalString.length < self.length)
[finalString replaceCharactersInRange:NSMakeRange(finalString.length - 3, 3) withString:#"..."];
return finalString;
}
The problem is that this sometimes cuts the string too short when it has room to spare. I think this is where that last condition comes in to play. How do I make sure it doesn't cut off too much?
Good news! There is a "computer science/mathematical way" to do this faster.
The example you link to does a linear search: it just chops one character at a time from the end of the string until it's short enough. So, the amount of time it takes will scale linearly with the length of the string, and with long strings it will be really slow, as you've discovered.
However, you can easily apply a binary search technique to the string. Instead of starting at the end and dropping off one character at a time, you start in the middle:
THIS IS THE STRING THAT YOU WANT TO TRUNCATE
^
You compute the width of "THIS IS THE STRING THAT". If it is too wide, you move your test point to the midpoint of the space on the left. Like this:
THIS IS THE STRING THAT YOU WANT TO TRUNCATE
^ |
On the other hand, if it isn't wide enough, you move the test point to the midpoint of the other half:
THIS IS THE STRING THAT YOU WANT TO TRUNCATE
| ^
You repeat this until you find the point that is just under your width limit. Because you're dividing your search area in half each time, you'll never need to compute the width more than log2 N times (where N is the length of the string) which doesn't grow very fast, even for very long strings.
To put it another way, if you double the length of your input string, that's only one additional width computation.
Starting with Wikipedia's binary search sample, here's an example. Note that since we're not looking for an exact match (you want largest that will fit) the logic is slightly different.
int binary_search(NSString *A, float max_width, int imin, int imax)
{
// continue searching while [imin,imax] is not empty
while (imax >= imin)
{
/* calculate the midpoint for roughly equal partition */
int imid = (imin + imax) / 2;
// determine which subarray to search
float width = ComputeWidthOfString([A substringToIndex:imid]);
if (width < max_width)
// change min index to search upper subarray
imin = imid + 1;
else if (width > max_width )
// change max index to search lower subarray
imax = imid - 1;
else
// exact match found at index imid
return imid;
}
// Normally, this is the "not found" case, but we're just looking for
// the best fit, so we return something here.
return imin;
}
You need to do some math or testing to figure out what's the right index at the bottom, but it's definitely imin or imax, plus or minus one.

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.