UITextField changes large numbers when inputted - ios

I noticed something weird in one of my applications and for some really reason, if I submit a small number, say 1,000,000,000, it will function normally but if I submit a large number, say 12,345,678,987,654,321, in this case it was 2147483647. So i set up a simple app that would just take the number and make it a label's text by
var theNum = textField.text.bridgeToObjectiveC().intValue
numLabel.text = "\(theNum)"
Now for smaller numbers it work but big numbers like the one above it doesn't. I should say that I am transferring the variables between views in case that has something to do with it. Also, I know the above code is in Swift but it does the same thing in Objective C. This is really messing with me because I can't find any reason that it would do this so all help will be appreciated!
Thanks

To hold some very large numbers or numbers with high precision you should use the NSDecimalNumber class. Note this is a class, not a primitive, you need to allocate it, call a stringValue to get the string and to do operations on it you again need to use methods. A short example:
NSDecimalNumber *number = [[NSDecimalNumber alloc] initWithString:textField.text];
textField.text = number.stringValue;
number = [number decimalNumberByAdding:[[NSDecimalNumber alloc] initWithInteger:10]];

Related

Swift: converting String to Float and back to String again after doing some mathematical operations

I've been googling and trying to understand how things work with the Float values in swift, but can't seem to make any sense of it, I would really appreciate any help, I feel I'm just wasting my time.
For example, let's say that I have an API that returns some json data, I parse that data, make some calculations and then present some of the data to the user, something like this:
let balance : String = "773480.67" // value that was received through json api
let commission : String = "100000.00" // value that was received through json api
//framework maps the json properties
let floatBalance : Float = Float(balance)! // at this point value is 773480.688
let floatCommission : Float = Float(commission)! //100000.0
//we do some math with the values
let result : Float = floatBalance + floatCommission // this is somehow 873480.687
//and then show some of the values on a label
print("stringBalance: \(balance)") //stringBalance: 773480.67
print("floatBalance: \(floatBalance)") //floatBalance: 773481.0
print("floatCommission: \(floatCommission)") //floatCommission: 100000.0
print("result: \(result)") //result: 873481.0
print("label: \(String(format:"%.2f", result))") //label: 873480.69
print("just kill me now")
I'm using the EVReflection framework to map the json properties to an object, so the conversion from String to Float is done in the background without me doing much about it, but the values shown above are basically what I'm working with.
My question is, what do I need to do at the end to get the correct string (873480.67) from the resulting float (873480.687) or is my approach wrong from the start?
Thank you
Actually floats can not represent numbers accurately, you'll have to use Double.
Here is a very nice answer on that issue:
https://stackoverflow.com/a/3730040/4662531
EDIT:
Sorry, but actually Double should not be use to perform calculations (I'm assuming from the naming of your variables you are working on some banking things). That part of the above linked answer is really giving a great suggestion:
A solution that works in just about any language is to use integers
instead, and count cents. For instance, 1025 would be $10.25. Several
languages also have built-in types to deal with money. Among others,
Java has the BigDecimal class, and C# has the decimal type.
A colleague of mine that used to work in a banking company also confirmed that all calculations were done without using Floats or Double, but with Int as suggested in the link.

How to print a random String in Swift in TextView?

I've stored several sentences in an array:
let sentences = ["This is example 2","This is the second example", "The last example"]
One of these string should be shown in my TextView by random.
Can you help me how I can do this with Swift?
I am answering this question keeping in mind a general approach. I am not keeping in mind the Programming language you are working on. Keeping in mind the time factor. Get the timestamp from system in milliseconds and take mod of 3 this way you will always get a random number in [0,1,2]
index = timestamp_in_milliseconds % 3
sentences[index]

Core Data Storing NSDecimalNumber with Precision

I'm receiving and parsing JSON and storing the data into Core Data. Some of the data is currency being stored as NSDecimalNumber, but some of these values have a higher precision than two decimal places.
For instance, if I get a value from the service such as 8.2399999995 I would like to store this in Core Data as 8.24. Is there any way to set up my model to a two decimal place precision? Or do I need to manually round each value after it's stored?
UPDATE
Leijonien thanks for the information. I tried to doing that and I'm having some trouble saving the formatted value. I checked the JSON and searched Google and it turns out I'm getting a clean value from the service. RESTKit is the problem....https://github.com/RestKit/RestKit/issues/1405.
However, I've created a category on one of my NSManagedObject classes, overridden the setter for the attribute I want, formatted the value, but I still see the long decimal value in my db. Here's my code.
- (void)setAmount:(NSDecimalNumber *)amount {
NSDecimalNumberHandler *round = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain
scale:2
raiseOnExactness:NO
raiseOnOverflow:NO
raiseOnUnderflow:NO
raiseOnDivideByZero:YES];
NSDecimalNumber *newAmount = [amount decimalNumberByRoundingAccordingToBehavior:round];
NSLog(#"%#", newAmount);
[self setPrimitiveValue:newAmount forKey:#"amount"];
}
What's weird is that when newAmount prints to the console it's in the format 8.24 like I want, but when I check the db it's saved as 8.2399999995. Am I doing something wrong here?
CoreData will just store the value you pass, so if you need only 2 digits, you should round the value yourself. Probably better to round the value before it's stored, so you only have to do it once per result.
As it turns out, the problem is not RESTKit. In fact, the problem appears to be Core Data. This is why printing to the console in my setter method printed the correctly formatted number, but the number has the wrong precision in the db. The best remedy for this situation was to override the getter method and format the number there, after it has been pulled from Core Data. The following seems to work...let me know if you've found anything else that works.
- (NSDecimalNumber*)amount {
[self willAccessValueForKey:#"amount"];
NSDecimalNumber* unroundedAmount = [self primitiveValueForKey:#"amount"];
[self didAccessValueForKey:#"amount"];
NSDecimalNumberHandler *round = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain
scale:2
raiseOnExactness:NO
raiseOnOverflow:NO
raiseOnUnderflow:NO
raiseOnDivideByZero:YES];
NSDecimalNumber *roundedAmount = [unroundedAmount decimalNumberByRoundingAccordingToBehavior:round];
return roundedAmount;
}
One thing to watch out for is that some (most?) decimal numbers can't be stored in floating-point binary in exactly the same way we think of them. There's alot to read on it out there, but I like the detailed approach of this one: http://www.cprogramming.com/tutorial/floating_point/understanding_floating_point_representation.html.
So for your number, the .24 can't be represented in floating-point because the binary can only give that the decimal component of a number is made up of .5, .25, .125, ... (that might be missing some special rules, but it's the general idea). So to represent .24 it uses as many of the lower values to get as close as it can.
NSDecimalNumber was set up to round it, but if you don't tell it to round anything you'll see the same 8.23999... value there too.

Which one is faster? for-loop or isEqualToArray

I would like to know what isEqualToArray actually does...
I have an array with size 160, each containing a dictionary with 11 entries, but I can do the comparison simply based on the first column (contains the date when the row was changed).
Now I can do that with a simple for-cycle:
BOOL different = FALSE;
for (int index = 0 ; index < [newInfo count] ; ++index)
if (![[[oldInfo objectAtIndex:index] objectForKey:#"Update"] isEqual:[[newInfo objectAtIndex:index] objectForKey:#"Update"]]) {
different = TRUE;
break;
}
if (different) {
}
else
NSLog(#"Contact information hasn't been updated yet");
Or I can use the built-in isEqualToArray method:
if ([oldInfo isEqualToArray:newInfo])
NSLog(#"Contact information hasn't been updated yet");
else {
NSLog(#"Contact information has been updated, saving new contact information");
[newInfo writeToFile:path atomically:YES];
}
Now, if assuming isEqualToArray just invokes isEqualTo for each cell, the for-loop method runs for 1/11 of the time isEqualToArray does (only need to compare one column instead of 11).
Maybe I'm just too much into optimizing... (I've been at many contests where runtime was limited and I'm feeling the after-effects).
The Documentation says:
Two arrays have equal contents if they each hold the same number of objects and objects at a given index in each array satisfy the isEqual: test.
So basically you are right.
From a design point of view I would either go for isEqualToArray:, since it makes the code easier to understand or introduce a BOOL hasUpdates if you are concern about performance, which has the additionally advantage that you don't have to hold two copies in memory.
I suspect that many people wrongly assume that performance is proportional to the number of source statements executed and that a function like isEqualToArray is blindingly fast compared to the equivalent directly-coded loop.
In fact, while sometimes the coders of these APIs do indeed know a few "tricks of the trade" that speed things up a bit (or have access to internal interfaces you can't use), just as often they must throw in additional logic to handle "oddball" cases that you don't care about, or simply to make the API "general".
So in most cases the choice should be based on which most reasonably fits the overall program and makes the logic clear. In some cases the explicit loop is better, especially if one can harness some of the logic (eg, to take a later-required "max" of the array values) to avoid duplication of effort.
Also, when there is a complex API function (more complex than isEqualToArray) you're not quite sure you understand, it's often better to code things in a straight-forward manner rather than deal with the complex function. Once you have the code working you can come back and "optimize" things to use the complex API.
When you know both objects are Arrays, isEqualTo<Class> method is a faster way to check equality than for loop.
isEqualTo<Class> is used to provide specific checks for equality.so isEqualToArray: checks that the arrays contain an equal number of objects.
So as per my knowledge i can say isEqualToArray is better option when you know that two objects are arrays.

Converting `NSDecimalNumber` to `SInt64` without precision loss. (within range of SInt64, iOS)

Currently, [NSDecimalNumber longLongValue] created with string #"9999999999999999" returns 10000000000000000.
This means the class converts it's value to double first, and re-converts into SInt64(signed long long)
How to evade this behavior? I want to get precise integral number within the range of SInt64.
PS.
I considered about converting to NSString and re-converting into SInt64 with NSScanner or strtoll, but I believe there's better way. But if you sure about there's no other way, please tell me that.
First: unless you're sure it's performance-critical, I'd write it into a string and scan it back. That's the easy way.
Now, if you really want to do it otherwise:
get an NSDecimal from your NSDecimalNumber
work with the private fields of the structure, initialize your long long value from the mantissa (possibly introduce checks to handle too-large mantissas)
multiply by 10^exponent; you can do that using binary exponentiation; again, check for overflow
Start with an NSDecimalNumber* originalValue.
Let int64_t approx = [originalValue longLongValue]. This will not be exact, but quite close.
Convert approx to NSDecimalNumber, calculate originalValue - approx, take the longLongValue, and add to approx. Now you got the correct result.

Resources