Take average of segments of NSArray - ios

I have an NSArray of 100 numbers. I would like to create an NSArray of 5 numbers. The first number in the second array is the average of the first 20 numbers in the first array. The second number is the average of the second set of 20 numbers in the first array. And so on.
I'm curious to hear people's ideas for an efficient algorithm.
One idea I had was to do a for-loop on each set of 20 numbers, creating a temp NSArray of 20 numbers. Then perform a KVO average operation and add to the final NSArray.
Note: I always award THE answer to someone, and I'm not shy to up vote your answers. I encourage many answers. Thanks!

Just add the values in each 20 number section, divide by 20 and put in the appropriate output array location. It is one pass through the array, Big O(n), what more could you ask for? The time to compute this is minuscule.

The following is simple and efficient:
NSArray *numbers = ... // array of 100 numbers
NSMutableArray *averages = [NSMutableArray array];
for (int = 0; i < 5; i++) {
float total = 0.0;
int base = i * 20;
for (int j = 0; j < 20; j++) {
float num = [numbers[base + j] floatValue];
total += num;
}
float avg = total / 20.0f;
[averages addObject:#(avg)];
}
NSLog(#"Averages = %#", averages);

you could try something like this...
NSArray *_array = // with the 100 numbers... (I used NSNumber object for each number)
NSMutableArray *_averages = [NSMutableArray array];
for (int i = 0; i < 5; i++) [_averages addObject:#([[[_array subarrayWithRange:NSMakeRange(i * 20, 20)] valueForKeyPath:#"#avg.floatValue"] floatValue])];
the _averages will contain 5 values with the averages of the five different sections of the 100 numbers.
UPDATED:
this part is just for eyes with extra curiosity.
if you tries to avoid the NSObjects and the double for loops, you could achieve a really fast algorithm, and of course when you go lower levels, you can improve the current speed as well, the question is: does it really need?
NSInteger _segments = 1000; // it means 20.000 numbers;
Float64 _numbers[(_segments * 20)]; // fill this array as you'd like.
Float64 _averages[_segments];
for (int i = 0; i < _segments; i++) {
NSInteger _offset = (_segments<<4)+4;
_averages[i] = (_numbers[_offset] + _numbers[_offset+1] + _numbers[_offset+2] + _numbers[_offset+3] + _numbers[_offset+4] + _numbers[_offset+5] + _numbers[_offset+6] + _numbers[_offset+7] + _numbers[_offset+8] + _numbers[_offset+9] + _numbers[_offset+10] + _numbers[_offset+11] + _numbers[_offset+12] + _numbers[_offset+13] + _numbers[_offset+14] + _numbers[_offset+15] + _numbers[_offset+16] + _numbers[_offset+17] + _numbers[_offset+18] + _numbers[_offset+19]) / 20.f;
}
it is 10 times faster than the solution with double for loops and NSObject classes.
(un)fortunately, it is not even the ugliest solution, but there is no question it is fast as hell, I won't recommend it except the speed really matter because that kind of solutions can provide really good efficiency.

Related

How to convert Uint8List to decimal number in Dart?

I have an Uint8List data list, for example:
Uint8List uintList = Uint8List.fromList([10, 1]);
How can I convert these numbers to a decimal number?
int decimalValue = ??? // in this case 265
Mees' answer is the correct general method, and it's good to understand how to do bitwise operations manually.
However, Dart does have a ByteData class that has various functions to help parse byte data for you (e.g. getInt16, getUint16). In your case, you can do:
Uint8List uintList = Uint8List.fromList([10, 1]);
int decimalValue = ByteData.view(uintList.buffer).getInt16(0, Endian.little);
print(decimalValue); // Prints: 266.
From what I understand of your question, you want decimalValue to be an integer where the least significant byte is (decimal)10, and the byte after that to be 1. This would result in the value 1 * 256 + 10 = 266. If you meant the bytes the other way around, it would be 10 * 256 + 1 = 2560 + 1 = 2561.
I don't actually have any experience with dart, but I assume code similar to this would work:
int decimalValue = 0;
for (int i = 0; i < uintList.length; i++) {
decimalValue = decimalValue << 8; // shift everything one byte to the left
decimalValue = decimalValue | uintList[i]; // bitwise or operation
}
If it doesn't produce the number you want it to, you might have to iterate through the loop backwards instead, which requires changing one line of code:
for (int i = uintList.length-1; i >= 0; i--) {

How to vectorize Mersenne Twister loops over arrays

Currently i'm working with an custom implementation of the Mersenne Twister, and i'd like to improve my understanding of vector operations.
I have the following code:
#define N 624
#define M 397
for( k = N -1; k; k-- )
{
array[i] = (array[i] ^ ((array[i-1] ^ (array[i-1] >> 30)) * 1566083941UL)) - i;
array[i] &= 0xffffffffUL;
++i;
if ( i >= N )
{
array[0] = array[N-1];
i = 1;
}
}
Here i'm working with 32 bit integers only, so as i understand, I could perform 8 times as much operations at the same time, using AVX2 instructions? How can I do that in practice?
I know how to deal with addition of 2 vectors, but this case seems to be more complicated. I don't know how to begin.
For a scalar approach i'd work like that, but i'd like to get sure how to perform these actions in my case.
for (i = 0; i < 1024; i++)
{
C[i] = A[i]*B[i];
}
for (i = 0; i < 1024; i+=4)
{
C[i:i+3] = A[i:i+3]*B[i:i+3];
}
Unfortunately at my university there are no lessons about intrinsics, but i'm quite curious in order to get an improvement.
I'm also doing some thoughts, about how to create the array using vectors? Maybe matrix? (Maybe _mm256_setr_epi32)
I hope to get some advice regarding this topic!

Objective-C - Wrong output on simple math

I am learning Objective-C and iOS development by making a simple tip calculator. However, the issue I am having is when I try to calculate the tip. This is simple math (tip percent / total bill) * 100. This is exactly what I am doing, but I am really confused as to why my output is wrong.
This is the method in my ViewController.m file that is giving me issues
- (IBAction)doCalculate:(id)sender {
NSInteger totalBillAmount = self.inputTotalBill.text.intValue;
NSLog(#"input total bill: %i", totalBillAmount);
NSInteger tipPercent = self.inputTip.text.intValue;
NSLog(#"input tip percent: %i", tipPercent);
NSInteger tipAmount = (tipPercent / totalBillAmount) * 100;
NSLog(#"tip amount: %i", tipAmount);
NSInteger billAmount = totalBillAmount + tipAmount;
NSLog(#"total bill: %i", billAmount);
// Set labels accordingly
self.labelTipAmount.text = [NSString stringWithFormat:#"%i", tipAmount];
self.labelBillAmount.text = [NSString stringWithFormat:#"%i", billAmount];
}
And this is my output:
2016-02-28 01:39:36.283 conversion[1533:58347] input total bill: 100
2016-02-28 01:39:36.285 conversion[1533:58347] input tip percent: 15
2016-02-28 01:39:36.285 conversion[1533:58347] tip amount: 0
2016-02-28 01:39:36.285 conversion[1533:58347] total bill: 100
I am really confused so any help is appreciated, thanks!
Computer numbers does not behave like numbers you learned at school. Integers only use integer arithmetic, and then integer division (look on the web).
4/100 (as an integer division) gives 0 (remember Euclidian division?) If you want to make more natural computations, use floats or doubles (but they will surprise you even more later!).
When you divide two NSIntegers, the result is one NSInteger. If that fraction is <1 and >0 then the output is 0. Using NSInteger might not be the best option here if you want it to be simple.
NSInteger tipAmount = (tipPercent * totalBillAmount) / 100;
NSLog(#"tip amount: %i", tipAmount); // tip amount: 0
If you used a float, it would be a whole lot cleaner:
float tipAmount = (tipPercent * totalBillAmount) / 100;
NSLog(#"tip amount: $%.02f", tipAmount); // tip amount: $15.00
However, using floats for currency can be very bad. So, it would be a more sage decision to use NSInteger to keep track of the smallest unit of currency instead. For the USD this is $0.001, or one tenth of a cent.
This means, when someone enters the bill total, let's say $100.00, you would record that value as 100000.
Then, to calculate 15%, you would multiply the bill by 15 and then divide by 100.
NSInteger tipAmount = (tipPercent * totalBillAmount) / 100;
NSLog(#"tip amount: %i", tipAmount); // tip amount: 15000
To show the user again, I would use a method like the following to convert from tenth cent units to a formatted string for dollars:
- (NSString *)tenthCentToDollarString:(NSInteger)tenthCents {
if (tenthCents >= 0) {
NSInteger roundedCents = (tenthCents + 5) / 10;
if (roundedCents < 10) {
return [NSString stringWithFormat:#"$0.0%zd", roundedCents];
}
if (roundedCents < 100) {
return [NSString stringWithFormat:#"$0.%zd", roundedCents];
}
NSInteger cents = roundedCents % 100;
NSInteger dollars = roundedCents / 100;
if (cents < 10) {
return [NSString stringWithFormat:#"$%zd.0%zd", dollars, cents];
}
return [NSString stringWithFormat:#"$%zd.%zd", dollars, cents];
}
// Dollar amount is negative
NSInteger positiveTenthCents = ABS(tenthCents);
NSString *dollarString = [self tenthCentToDollarString:positiveTenthCents];
return [NSString stringWithFormat:#"-%#", dollarString];
}
A couple issues: You should be doing tipAmount = (tipPercent / 100) * totalBillAmount and cast to doubles because NSInts can't do fractions.

Subarray with range

Im trying to split an array of objects into smaller arrays containing 32 objects. With the remaining about being put into the array at the end.
This is the code I'm using
int a = sharedManager.inventoryArray2.count;
float b = a / 33;
int c = ceilf(b);
NSMutableArray *arrayOfArrays = [NSMutableArray array];
int from = 0;
int to = 31;
for (int e = 0; e <= c; e++) {
if (sharedManager.inventoryArray2.count < to) {
NSArray *smallArray = [sharedManager.inventoryArray2 subarrayWithRange:NSMakeRange(from, sharedManager.inventoryArray2.count)];
[arrayOfArrays addObject:smallArray];
}
else {
NSArray *smallArray = [sharedManager.inventoryArray2 subarrayWithRange:NSMakeRange(from, to)];
from = from + (31+1);
to = from + 31;
[arrayOfArrays addObject:smallArray];
}
}
I'm getting the following error.
'NSRangeException', reason: '*** -[NSArray subarrayWithRange:]: range {32, 63} extends beyond bounds [0 .. 83]'
I don't get it, the range of 32-63 is in the bounds of 0-83.
Any advice?
Thanks.
Paul.
A NSRange indicates the starting point and the number of entries to select from that point on.. So it actually means "Starting point 32, select 63 items from that point on", which will exceed your 83 entries (32 + 63)
2nd parameter of NSMakeRange is length range to create, not the last index in it. So you need to change your code accordingly (simplifying it a bit):
NSUInteger count = sharedManager.inventoryArray2.count;
NSMutableArray *arrayOfArrays = [NSMutableArray array];
NSUInteger from = 0;
while (from < count) {
NSRange range = NSMakeRange(from, MIN(32, count-from));
NSArray *smallArray = [sharedManager.inventoryArray2 subarrayWithRange:range];
[arrayOfArrays addObject:smallArray];
from += 32;
}
No Actually the range doesn't work like this
NSRange {32, 63} => means from the index 32 take 63 elements
Here is documentation :
NSRange
A structure used to describe a portion of a series—such as characters in a string or objects in an NSArray object.
typedef struct _NSRange {
NSUInteger location;
NSUInteger length;
} NSRange;
location
The start index (0 is the first, as in C arrays). For type compatibility with the rest of the system, LONG_MAX is the maximum value you should use for location.
length
The number of items in the range (can be 0). For type compatibility with the rest of the system, LONG_MAX is the maximum value you should use for length.

How to Increment numbers in an array to populate UIPickerView

I have a UIPickerView that I am populating with an array. It has two columns and i need the first column to go from 50-500. the second column to go from 0.01 to 1. The point is for the user to pick their weight. For doing the 50-500 I have this,
-(void)populateWeightPickerArray{
weightPickerArray = [[NSMutableArray alloc] init];
for (int weight = 50; weight <=500; weight++) {
NSString *weightString = [NSString stringWithFormat:#"%d%",weight];
[weightPickerArray addObject:weightString];
}
}
I tried doing that with the decimal, however when i use ++ it goes up by whole number and I end up getting 1.01, 2.01, 3.01 etc. here is what I have for code.
-(void)populateWeightPickerArray2{
weightPickerArray2 = [[NSMutableArray alloc] init];
for (float weightDecimal = .01; weightDecimal <= 10; weightDecimal++) {
NSString *weightDecimalString = [NSString stringWithFormat:#"%0.2f",weightDecimal];
[weightPickerArray2 addObject:weightDecimalString];
}
}
(I know i said I only needed it to go to 1 not 10, but i put 10 because at first it was only displaying 1.01, so i put 10 to test the output until I can get it right.)
So i need to somehow increment it to make it go from .01 to 1 (0.02, 0.03,0.04 etc). Anyone know how to do this?
for (float weightDecimal = .01; weightDecimal <= 10; weightDecimal = weightDecimal + 0.01)
or more succinctly:
for (float weightDecimal = .01; weightDecimal <= 10; weightDecimal += 0.01)
In Objective C: x += y is a shorthand for x = x + y.
Although you often see for loops with something++ or something-- you can use any expression.

Resources