Trying to make my objective-c program more efficient; Beginner - objective-c

#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int number, right_digit;
NSLog(#"Enter your number.");
scanf("%i", &number);
while (number != 0) {
right_digit = number % 10;
if (right_digit <0 && number <10 && number>-10) {
right_digit = -right_digit;
NSLog(#"%i- ", right_digit);
}
else if (right_digit<0) {
right_digit = -right_digit;
NSLog(#"%i", right_digit);
}
else {
NSLog(#"%i", right_digit);
}
number /=10;
}
[pool drain];
return 0;
}
The aforementioned code works insofar as finding the reverse of a number, both negative and positive. If negative, say for example, -1234, the answer is supposed to read 4321-. I have no problems there. I am just learning Objective-C so I understand if this is a basic question and my code is very basic. The problem is I have some repeating code and I'm sure there is a better way to write this. I just wanted to know if someone could give me any insight.

I'd do it this way:
NSInteger number = -12;
NSUInteger inverse = 0;
NSInteger sign = (number >= 0) ? 1 : -1;
number = number * sign;
while (number > 0)
{
inverse = inverse * 10 + (number % 10);
number = number / 10;
}
NSLog(#"%i%#", inverse, (sign == -1) ? #"-" : #"");

Without critiquing the details of the algorithm (I might have done it differently, and I haven't evaluated it for correctness/robustness) I can't see anything that would be regarded as "inefficient".
Necessarily you're going to have to iterate through each digit, and you don't appear to iterate more than necessary. The logic is all (save for the actual output) "scalar" (not-object) integer values, so no unnecessary object creation. At most you might be able to eliminate one or two of the tests in your if statements, but there's little efficiency gain there. And I can't see how using any Cocoa classes might have made it simpler.

Related

Count number of zero(0) using objective-c

I want to count how many number of zero(0) before numeric number. Because I need to save those number which is present before numeric.
Exam:- suppose I have a number 0000102. So I want to calculate how many zero(0) before numeric start. In this exam we are see here is 4 zero's(0) are present. It is possible to calculate this?
for (i=0;i<string.length;i++)
{
if ([[string characterAtIndex:i] intValue] <= 9 || [[string characterAtIndex:i] intValue] > 0 )
{
i++;
}
else
{
numerOfZeros++;
}
}
int count = 0;
NSString *strr = #"0000102";
unichar findC;
for (int i = 0; i<strr.length; i++)
{
findC = [strr characterAtIndex:i];
if (findC == '0')
{
count++;
}
else
break;
}
NSLog(#"%d",count);
Recursive approach for a one liner:
#implementation NSString (category)
- (NSUInteger)zeroPrefixCount
{
return [string hasPrefix:#"0"] ? 1 + [[string substringFromIndex:1] zeroPrefixCount] : 0;
}
#end
This is not an optimal solution, performance-wise, but it's typical of your first days at programming classes.
usage
// x will be 4
NSUInteger x = [#"0000102" zeroPrefixCount];
I recommend you to save this kind of numbers as String itself and no need to further evaluate how many zeros are there rather do a string comparison if needed.
If you really want to count zeros in your number then you can consider converting it to a string and use NSRange and NSString helper methods to get what you want. Similar situation is answered here.
search if NSString contains value

Objective-C source code debug: Thread Error

I cannot seem to solve this problem, im not sure what it is at this point but the tread error wont go away. I cant seem to find what im doing wrong.
This code may be a handful to read (sorry) but its very simple. I'am basically invoking a function from main and passing an array of function values, from there im passing two fractions at a time to a method so it find the LCM(least common multiple) using the denominators and return the value. But a thread error seems to be occurring at the call to the findLCM method from function at the point of where the method is declared.
#interface Fraction: NSObject
#property int numerator, denominator;
-(Fraction *)findLCM:(Fraction *)fraction withXFractions:(int)Xfraction;
#implementation Fraction
-(Fraction *)findLCM:(Fraction *)fraction withXFractions:(int)Xfraction{
int lcmOfFraction = 0;
int a, b;
a = fraction.denominator;
b = self.denominator;
int max =(a>b) ? a : b; // get max value out of the two denominators.
for (int i = 0; i < Xfraction; i++) {
while(1) /* Always true. */
{
if(max%a==0 && max%b==0)
{ lcmOfFraction = max;
break; /* while loop terminates. */
}
++max;
}
}
Fraction *lcmDenominator = [Fraction new];
[lcmDenominator setTo:0 over:max]; //passing just LCM (denominator of 2 fractions)
return lcmDenominator;
}
Fraction *addFraction(Fraction **arrayOfFractions, int arraySize) {
Fraction *LCM = [[Fraction alloc] init];
int lcmOfFractions = 0;
[LCM setTo:0 over:1];
for (int i = 0; i <= arraySize; i++) {
LCM = [LCM findLCM:arrayOfFractions[i] withXFractions:4];
//^gets the LCM (the common denominator)
}
return LCM;
}
int main () {
#autoreleasepool {
[frac1 setTo:2 over:12]; [frac2 setTo:2 over:4];
[frac3 setTo:6 over:8]; [frac4 setTo:8 over:3];
Fraction __autoreleasing *arrayOfFractions[4] = {frac1, frac2, frac3, frac4 };
Fraction *LCMFraction = addFraction(arrayOfFractions, 4);
//common LCM return
}
}
You create no threads in this code. When asking a question like this you should clearly explain what the error is, and what you have tried to find its source. People may then be able to help you.
Some hints/suggestions:
use breakpoints to stop your code during execution to allow you to examine the values of your variables
pay close attention to indexing operations, you are using a C array and those do not do bounds checking
ask whether using a C array here, rather than an NSArray is your best choice. Note there is nothing wrong with using C arrays when appropriate.
__autoreleasing probably doesn't mean what you think it does, it is rare to see this used explicitly in user code.
If you have a specific question when you've got further ask a new question on SO, somebody will probably be able to help you out.
HTH

Convert really large decimal string to hex?

I've got a really large decimal number in an NSString, which is too large to fit into any variable including NSDecimal. I was doing the math manually, but if I can't fit the number into a variable then I can't be dividing it. So what would be a good way to convert the string?
Example Input: 423723487924398723478243789243879243978234
Output: 4DD361F5A772159224CE9EB0C215D2915FA
I was looking at the first answer here, but it's in C# and I don't know it's objective C equivalent.
Does anyone have any ideas that don't involve using an external library?
If this is all you need, it's not too hard to implement, especially if you're willing to use Objective-C++. By using Objective-C++, you can use a vector to manage memory, which simplifies the code.
Here's the interface we'll implement:
// NSString+BigDecimalToHex.h
#interface NSString (BigDecimalToHex)
- (NSString *)hexStringFromDecimalString;
#end
To implement it, we'll represent an arbitrary-precision non-negative integer as a vector of base-65536 digits:
// NSString+BigDecimalToHex.mm
#import "NSString+BigDecimalToHex.h"
#import <vector>
// index 0 is the least significant digit
typedef std::vector<uint16_t> BigInt;
The "hard" part is to multiply a BigInt by 10 and add a single decimal digit to it. We can very easily implement this as long multiplication with a preloaded carry:
static void insertDecimalDigit(BigInt &b, uint16_t decimalDigit) {
uint32_t carry = decimalDigit;
for (size_t i = 0; i < b.size(); ++i) {
uint32_t product = b[i] * (uint32_t)10 + carry;
b[i] = (uint16_t)product;
carry = product >> 16;
}
if (carry > 0) {
b.push_back(carry);
}
}
With that helper method, we're ready to implement the interface. First, we need to convert the decimal digit string to a BigInt by calling the helper method once for each decimal digit:
- (NSString *)hexStringFromDecimalString {
NSUInteger length = self.length;
unichar decimalCharacters[length];
[self getCharacters:decimalCharacters range:NSMakeRange(0, length)];
BigInt b;
for (NSUInteger i = 0; i < length; ++i) {
insertDecimalDigit(b, decimalCharacters[i] - '0');
}
If the input string is empty, or all zeros, then b is empty. We need to check for that:
if (b.size() == 0) {
return #"0";
}
Now we need to convert b to a hex digit string. The most significant digit of b is at the highest index. To avoid leading zeros, we'll handle that digit specially:
NSMutableString *hexString = [NSMutableString stringWithFormat:#"%X", b.back()];
Then we convert each remaining base-65536 digit to four hex digits, in order from most significant to least significant:
for (ssize_t i = b.size() - 2; i >= 0; --i) {
[hexString appendFormat:#"%04X", b[i]];
}
And then we're done:
return hexString;
}
You can find my full test program (to run as a Mac command-line program) in this gist.

Prime Generator not working

I want to write a really simple prime app. But i am having some problems with the code below it should generate primes from 0 to 99. But instead it just shows 99.
One problem is that only the last number is displayed. But the other one is that the prime "check" doesn't work. How can I fix those problems.
for (i=0; i<100; i++) {
for (n=2; n<i; n++) {
if (i%n == 0) break;
else primetext.text = [NSString stringWithFormat:#"%i, ", i];
}
}
There were a number of problems, I'll try to explain them
The problem with prime checking was that you had the if-else statement inside of the for loop that iterated through the numbers to check. So if your number wasn't divisible by ANY of the numbers you check it would be registered as prime. It would also be registered n times, where n is the number of times it was found to not be divisible.
All even numbers are not prime (aside from 2), so you can do i+=2 to double your speed
You only need to check up to the square root of a number to see if it's prime.
1 isn't a prime so you don't need to include it (especially because it can make your logic more complex).
You were reassigning the string instead of adding a component to it
You were using %i instead of %d. This can sometimes cause weird errors.
Here is your method revised with these points in mind.
int maxNum = 100;
primetext.text = #"2 "; //Start knowing that 2 is the lowest prime (avoid evaluating evens)
for (i=3; i<=maxNum; i+=2) //Start at 3 and add 2 (avoid 1 and 2 as well as even numbers)
{
bool isPrime = YES; //Assume that i is prime
for (n=2; n<sqrt(i); n++) //Divide by every number up to square root
{
if (i%n == 0) //If evenly divisible by n, not a prime
{
isPrime = NO;
break; //Don't need to check any more factors, so break
}
}
if (isPrime) //If isPrime was never set to NO, i is prime
{
NSString *temp = [NSString stringWithFormat:#"%d ", i];
primetext.text = [primetext.text stringByAppendingString:temp];
}
}
Hope this helps.
You should append the number to primetext.text instead of assigning. Right now it's being reassigned on every iteration.

Quickest way to be sure region of memory is blank (all NULL)?

If I have an unsigned char *data pointer and I want to check whether size_t length of the data at that pointer is NULL, what would be the fastest way to do that? In other words, what's the fastest way to make sure a region of memory is blank?
I am implementing in iOS, so you can assume iOS frameworks are available, if that helps. On the other hand, simple C approaches (memcmp and the like) are also OK.
Note, I am not trying to clear the memory, but rather trying to confirm that it is already clear (I am trying to find out whether there is anything at all in some bitmap data, if that helps). For example, I think the following would work, though I have not tried it yet:
- BOOL data:(unsigned char *)data isNullToLength:(size_t)length {
unsigned char tester[length] = {};
memset(tester, 0, length);
if (memcmp(tester, data, length) != 0) {
return NO;
}
return YES;
}
I would rather not create a tester array, though, because the source data may be quite large and I'd rather avoid allocating memory for the test, even temporarily. But I may just being too conservative there.
UPDATE: Some Tests
Thanks to everyone for the great responses below. I decided to create a test app to see how these performed, the answers surprised me, so I thought I'd share them. First I'll show you the version of the algorithms I used (in some cases they differ slightly from those proposed) and then I'll share some results from the field.
The Tests
First I created some sample data:
size_t length = 1024 * 768;
unsigned char *data = (unsigned char *)calloc(sizeof(unsigned char), (unsigned long)length);
int i;
int count;
long check;
int loop = 5000;
Each test consisted of a loop run loop times. During the loop some random data was added to and removed from the data byte stream. Note that half the time there was actually no data added, so half the time the test should not find any non-zero data. Note the testZeros call is a placeholder for calls to the test routines below. A timer was started before the loop and stopped after the loop.
count = 0;
for (i=0; i<loop; i++) {
int r = random() % length;
if (random() % 2) { data[r] = 1; }
if (! testZeros(data, length)) {
count++;
}
data[r] = 0;
}
Test A: nullToLength. This was more or less my original formulation above, debugged and simplified a bit.
- (BOOL)data:(void *)data isNullToLength:(size_t)length {
void *tester = (void *)calloc(sizeof(void), (unsigned long)length);
int test = memcmp(tester, data, length);
free(tester);
return (! test);
}
Test B: allZero. Proposal by Carrotman.
BOOL allZero (unsigned char *data, size_t length) {
bool allZero = true;
for (int i = 0; i < length; i++){
if (*data++){
allZero = false;
break;
}
}
return allZero;
}
Test C: is_all_zero. Proposed by Lundin.
BOOL is_all_zero (unsigned char *data, size_t length)
{
BOOL result = TRUE;
unsigned char* end = data + length;
unsigned char* i;
for(i=data; i<end; i++) {
if(*i > 0) {
result = FALSE;
break;
}
}
return result;
}
Test D: sumArray. This is the top answer from the nearly duplicate question, proposed by vladr.
BOOL sumArray (unsigned char *data, size_t length) {
int sum = 0;
for (int i = 0; i < length; ++i) {
sum |= data[i];
}
return (sum == 0);
}
Test E: lulz. Proposed by Steve Jessop.
BOOL lulz (unsigned char *data, size_t length) {
if (length == 0) return 1;
if (*data) return 0;
return memcmp(data, data+1, length-1) == 0;
}
Test F: NSData. This is a test using NSData object I discovered in the iOS SDK while working on all of these. It turns out Apple does have an idea of how to compare byte streams that is designed to be hardware independent.
- (BOOL)nsdTestData: (NSData *)nsdData length: (NSUInteger)length {
void *tester = (void *)calloc(sizeof(void), (unsigned long)length);
NSData *nsdTester = [NSData dataWithBytesNoCopy:tester length:(NSUInteger)length freeWhenDone:NO];
int test = [nsdData isEqualToData:nsdTester];
free(tester);
return (test);
}
Results
So how did these approaches compare? Here are two sets of data, each representing 5000 loops through the check. First I tried this on the iPhone Simulator running on a relatively old iMac, then I tried this running on a first generation iPad.
On the iPhone 4.3 Simulator running on an iMac:
// Test A, nullToLength: 0.727 seconds
// Test F, NSData: 0.727
// Test E, lulz: 0.735
// Test C, is_all_zero: 7.340
// Test B, allZero: 8.736
// Test D, sumArray: 13.995
On a first generation iPad:
// Test A, nullToLength: 21.770 seconds
// Test F, NSData: 22.184
// Test E, lulz: 26.036
// Test C, is_all_zero: 54.747
// Test B, allZero: 63.185
// Test D, sumArray: 84.014
These are just two samples, I ran the test many times with only slightly varying results. The order of performance was always the same: A & F very close, E just behind, C, B, and D. I'd say that A, F, and E are virtual ties, on iOS I'd prefer F because it takes advantage of Apple's protection from processor change issues, but A & E are very close. The memcmp approach clearly wins over the simple loop approach, close to ten times faster in the simulator and twice as fast on the device itself. Oddly enough, D, the winning answer from the other thread performed very poorly in this test, probably because it does not break out of the loop when it hits the first difference.
I think you should do it with an explicit loop, but just for lulz:
if (length == 0) return 1;
if (*pdata) return 0;
return memcmp(pdata, pdata+1, length-1) == 0;
Unlike memcpy, memcmp does not require that the two data sections don't overlap.
It may well be slower than the loop, though, because the un-alignedness of the input pointers means there probably isn't much the implementation of memcmp can do to optimize, plus it's comparing memory with memory rather than memory with a constant. Easy enough to profile it and find out.
Not sure if it's the best, but I probably would do something like this:
bool allZero = true;
for (int i = 0; i < size_t; i++){
if (*data++){
//Roll back so data points to the non-zero char
data--;
//Do whatever is needed if it isn't zero.
allZero = false;
break;
}
}
If you've just allocated this memory, you can always call calloc rather than malloc (calloc requires that all the data is zeroed out). (Edit: reading your comment on the first post, you don't really need this. I'll just leave it just in case)
If you're allocating the memory yourself, I'd suggest using the calloc() function. It's just like malloc(), except it zeros out the buffer first. It's what's used to allocate memory for Objective-C objects and is the reason that all ivars default to 0.
On the other hand, if this is a statically declared buffer, or a buffer you're not allocating yourself, memset() is the easy way to do this.
Logic to get a value, check it, and set it will be at least as expensive as just setting it. You want it to be null, so just set it to null using memset().
This would be the preferred way to do it in C:
BOOL is_all_zero (const unsigned char* data, size_t length)
{
BOOL result = TRUE;
const unsigned char* end = data + length;
const unsigned char* i;
for(i=data; i<end; i++)
{
if(*i > 0)
{
result = FALSE;
break;
}
}
return result;
}
(Though note that strictly and formally speaking, a memory cell containing a NULL pointer mustn't necessarily be 0, as long as a null pointer cast results in the value zero, and a cast of a zero to a pointer results in a NULL pointer. In practice, this shouldn't matter as all known compilers use 0 or (void*) 0 for NULL.)
Note the edit to the initial question above. I did some tests and it is clear that the memcmp approach or using Apple's NSData object and its isEqualToData: method are the best approaches for speed. The simple loops are clearer to me, but slower on the device.