Objective C Math - Geometric sequence results - objective-c

For my app (OSX, not IOS) i have a geometric sequence (stored in container array) generated like this:
- (void)initContainerFor:(NSInteger)maxRows
{
self.container = [[NSMutableArray alloc] init];
NSInteger start = [self.firstTextFieldValue integerValue];
NSInteger ratio = [self.secondTextFieldValue integerValue];
// ASCENDING
for (NSInteger i = 1; i < (maxRows +1 ); i++)
{
NSInteger currentValue = start * pow(ratio,i-1);
[self.container addObject:currentValue];
}
}
User can enter the "start" and "ratio" integer. I want to give a feedback if limit (MAX_INT) is exceeded. I wrote this function:
- (BOOL)maxCheck
{
if ([self.container lastObject] > INT_MAX)
return false;
return true;
}
But this seems not to work. If i enter 2 for start and 200 for ratio i have this container content:
Container: (
2,
400,
80000,
16000000,
"-1094967296",
49872896,
1384644608,
2051014656,
"-2113929216",
0
)
Please help to understand what i see in the container (strings??) and how to get a correct check for the maximum value.

As you can see from log of array, you actually exceed INT_MAX limit twice, when next element become negative. So you can just add check to initContainer: method - if element is less then the previous, INT_MAX limit is reached.
TIP: INT_MAX is a signed value.

You can not compare the value after overflow with INT_MAX, as the overflow already happened. Or put differently, by its very definition and semantics, no integer can be bigger than INT_MAX.
What you can test is
[self.container lastObject] > INT_MAX/ratio
to find the sequence element that would cause overflow in the next step.

Related

Compare two CGSize's to best persentage

Need your help, I have input CGSize (for example): 200x300. And array with other CGSize's = [20x20, 100x100, 150x150, 200x100, 200x250, 300x300...].
Please help me to find best item in array that have best compare percentage (for example its 200x250)...
I tried to use for enumerator, for example:
CGSize inputSize = CGSizeMake(200, 300);
for (int i = 0; i < array.count; i++)
{
CGSize concurentSize = CGSizeZero;
switch (i)
{
case 0:
{
concurentSize.width = 20;
concurentSize.height = 20;
}
and so on...
float differencePercentWidth = ( concurentSize.width / inputSize.width ) * 100.0;
float differencePercentHeight = ( concurentSize.height / inputSize.height ) * 100.0;
if (differencePercentWidth > 90 && differencePercentHeight > 90)
{
// FOUND best CGSize... stop
break.
}
}
But, its not working, it differencePercentWidth/differencePercentHeight can be > 100 =(
I need some of method or function that can compare 2 CGSize's in percent match... For example: size 200x300 is best matches with size 200x250... Something like:
float matchesInPerсent = CGSizeCompare(firstCGSize, secondCGSize);
//matchesInPerсent = 0.6; // in percents
Please help, sorry for my english, if you need more details, please let me know. Thanks.
Try the similar logic to calculate the maximum number in the array, but need to less then one finite value. In this cases calculate maximum percentage average of size.width and size.height, the maximum percentage which is closes to 1 is the winner. If you need the upper value of the 100% as well then you need to insert the logic to take that value below the 100% and run the same logic on those sizes as well.
Here is code which will give you closest percentage size from the array.
/*
sizes : array of the sizes represented in NSValue format
size: The size for which you need closest value.
*/
- (CGSize)bestMatch:(NSArray *)sizes withSize:(CGSize)size {
float bestMatch = 0.0;
CGSize bestMatchSize = CGSizeZero;
for (NSValue *value in sizes) {
float percentage = (value.CGSizeValue.width/size.width + value.CGSizeValue.height/size.height)/2;
//If you need greater then 100% and closes to the size
if (percentage > 1.0) {
percentage = -1*(percentage - 2);
}
if (bestMatch < percentage && percentage < 1) {
bestMatch = percentage;
bestMatchSize = value.CGSizeValue;
}
}
//If you need best match you can return bestMatch which is closest in percentage
return bestMatchSize;
}

Pick a next item from NSArray and then start over

I need to toggle three different font sizes in the view controller for terms and conditions screen in an endless loop (13 , 15, 17..13, 15, 17..etc..). The screen is pretty simple, just text on full screen and a button in the navigation bar that when pressed, triggers and event handled in action.
The three fonts are represented by three NSString constants.
-(IBAction)toggleFontSize:(id)sender
{
if (self.currentFontIdentifier == regularFontIdentifier)
{
self.currentFontIdentifier = largeFontIdentifier;
}
else if (self.currentFontIdentifier == largeFontIdentifier)
{
self.currentFontIdentifier = smallFontIdentifier;
}
else
{
self.currentFontIdentifier = regularFontIdentifier;
}
self.termsAndConditionsTextView.font = [[BrandingManager sharedManager] fontWithIdentifier:self.currentFontIdentifier];
}
This code works (for now :)), but it's a nice Mediterranean IF yacht.I am wondering if there is some more mature approach. I already see the stakeholders changing their mind and adding a 4th font size. I want it to be manageable better, so basically once they add a new size I would only add it into some Array and that would be it.
Any ideas for a more mature algorithm?
Declare an instance variable for the current selected index and an array for the three fonts (small, regular and large) and try this:
-(IBAction)toggleFontSize:(id)sender {
_currentSelectedIndex = (_currentSelectedIndex + 1) % 3;
self.currentFontIdentifier = _fontIdentifiers[_currentSelectedIndex];
self.termsAndConditionsTextView.font = [[BrandingManager sharedManager] fontWithIdentifier:self.currentFontIdentifier];
}
You may not need currentFontIdentifier property since it can be obtained with _fontIdentifiers[_currentSelectedIndex]
You could use the methods 'indexOfObject and 'lastObject' of the NSArray class, something like:
Using an array of sizes:
NSArray *fontList = #[#"12","14","18"];
Then you could iterate through it using the indexOfObject
NSUInteger ix = [fontList indexOfObject:self.currentFontIdentifier] + 1;
if ([[fontList lastObject] isEqual:self.currentFontIdentifier])
ix=0;
self.currentFontIdentifier = [fontList objectAtIndex:ix];
or
NSUInteger ix = [fontList indexOfObject:self.currentFontIdentifier] + 1;
if (ix >= [fontList count])
ix=0;
self.currentFontIdentifier = [fontList objectAtIndex:ix];

"Weighted" random number generator

I'm currently using the below code to grab a random element from an array. How would I go about changing the code so that it returns an element weighted on the percentage that I want it to come up? For example, I want the element at index 0 to come up 27.4% of the time, but the element at index 7 to come up only 5.9% of the time.
NSArray *quoteArray = #[ #"quote1", #"quote2", #"quote3", #"quote4", #"quote5", #"quote6", #"quote7", #"quote8", ];
NSString *quoteString;
int r = arc4random() % [quoteArray count];
if(r<[rewardTypeArray count])
quoteString = [quoteArray objectAtIndex:r];
I would use an array of float (wrapped into NSNumber) objects.
Every object represents a percentage.In this case you would have an array of 8 objects:
Object 1: #27.5 ;
...
Object 7: #5.9 .
Then you get a random number from 1 to 100. If you want more precision you can also get a random number with the decimal part, and the precision doesn't influence the efficiency and neither the memory used.
Then when you get the number you iterate through all the array, keep track of the index and the percentage that you have. You use a float to sum all the percentages met and you stop only when the total percentage is greater on equal that the one that you have.
Example
NSArray* percentages= #[ #27.4 , ... , #5.9];
float randomNumber= arc4random_uniform(100) + (float)arc4random_uniform(101)/100;
NSUInteger n=0;
float totalPercentage= 0.0;
for(NSUInteger i=0; i<percentages.count; i++)
{
totalPercentage+= [ percentages[i] floatValue ];
if( totalPercentage >= randomNumber) // This case we don't care about
// the comparison precision
{
break;
}
n++;
}
// Now n is index that you want
The easiest way would be to generate a random number based on how fine-grained you want the percentage to be. To calculate to the tenth of a percent, you could generate between 0-1000, and 274 of the values you could randomly generate would be the first element. 59 values would correspond to element 7.
For example:
0-273 = index 1 27.4%
274-301 = index 2 2.7%
302-503 = index 3 20.1%
504-550 = index 4 4.6%
551-700 = index 5 14.9%
701-941 = index 6 24%
942-1000 = index 7 5.9%
The percentages don't add up properly, so I did my math wrong somewhere, but you get the point.
You can make another array with counter that would keep tracking how many times each one of your elements is being generated. If that counter is less than your target let that index come in your r, otherwise regenarate.

Using NSStepper to set ceiling value instead of incrementing value

I am using a NSStepper along with a NSTextField. The user can either set the value using the text field or can use the NSStepper to change the value. I will quote my question using the example below:
Suppose the current value of my stepper is 4 and increment value of the stepper is 2:
After I click the UP arrow on the NSStepper the value becomes:
Now Suppose the current value would have been 4.5 i.e.:
After using the UP arrow the value becomes:
What I require is that when the current value is 4.5, after using the UP arrow, the value becomes 6 instead of 6.5
Any ideas to accomplish this are highly appreciated!
What I require is that when the current value is 4.5, after using the
UP arrow, the value becomes 6 instead of 6.5
Hard to tell exactly what you are asking but taking a guess: it sounds like you want to remove the decimal part of the number and increment by your defined step amount (2). You can do this through the floor() function. See here for other Objective-C math functions
double floor ( double ) - removes the decimal part of the argument
NSLog(#"res: %.f", floor(3.000000000001));
//result 3
NSLog(#"res:%.f", floor(3.9999999));
//result 3
If I understand what you want, this code will give you the next even number (up or down depending on which arrow you click), but still allow you to enter non-integer numbers in the text filed. tf and stepper are IBOutlets and num is a property (a float) that keeps track of the value of the stepper before you click an arrow so you can compare with the new number to see if the up or down arrow was clicked.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
self.num = 0;
self.tf.intValue = 0; //the stepper is set to 0 in IB
}
-(IBAction)textFieldDidChange:(id)sender {
self.num = self.stepper.floatValue = [sender floatValue];
}
-(IBAction)stepperDidChange:(id)sender {
if (self.num < self.stepper.floatValue) { //determines whether the up or down arrow was clicked
self.num = self.stepper.intValue = self.tf.intValue = [self nextLargerEven:self.num];
}else{
self.num = self.stepper.intValue = self.tf.intValue =[self nextSmallerEven:self.num];
}
}
-(int)nextLargerEven:(float) previousValue {
if ((int)previousValue % 2 == 0) {
return (int)previousValue + 2;
}else
return (int)previousValue + 1;
}
-(int)nextSmallerEven:(float) previousValue {
if ((int)previousValue % 2 == 0) {
if ((int)previousValue == previousValue) {
return (int)previousValue - 2;
}else{
return (int)previousValue;
}
}else
return (int)previousValue - 1;
}

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.