NSExpression 1/2 - objective-c

I want to calculate a string, which I'm doing by this:
NSExpression *expression = [NSExpression expressionWithFormat:calculationString];
float result = [[expression expressionValueWithObject:nil context:nil] floatValue];
NSLog(#"%f", result);
The problem is, when calculationstring is 1/2, the result is 0. I tried to change float with double and NSNumber and the %f to %f and %#, but I always just get 0. What to I have to change?
Also if it matters, I am in Europe, so I have commas instead of points for this value, but it shouldn't matter as I am logging with %f which shows it as points. Just for information

Basically, you just need to tell it that you are performing floating point operation,
1.0/2
1.0/2.0
1/2.0
Will all work

Typing in NSExpression is much like in C: literals that look like integers (no decimal point/comma) are treated as integers and thus use integer division. (Under integer division, 1/2 is zero. If you want 0.5, you need floating point division.) This happens when the expression is parsed and evaluated, so attempting to change the type of the result or the formatting of the output has no effect -- those things happen after parsing and evaluation.
If your calculationString is entirely under your control, it's easy to make sure that you use floating point literals anywhere you want floating point division. (That is, use 1.0/2 instead of 1/2.) If not, you'll need to change it such that it does -- here it's probably better to decompose the parsed NSExpression and change an operand rather than munge the string.
Followup edit on the "decompose" bit: String munging in content that you know to have higher-order structure is generally problematic. And with NSExpression, you already have a parser (who's smarter than a simple regex) decomposing the string for you — that is in fact what NSExpression is all about.
So, if you're working with a user-provided string, don't try to change the expression by changing the string. Let NSExpression parse it, then use properties of the resulting object to pick it apart into its constituent expressions. If your string is simply "1/2", then your expression has an array of two arguments and the function "divide:by:" — you can replace it with an equivalent function where one of the arguments is explicitly a floating-point value:
extension NSExpression {
var floatifiedForDivisionIfNeeded: NSExpression {
if function == "divide:by:", let args = arguments, let last = args.last,
let firstValue = args.first?.constantValue as? NSNumber {
let newFirst = NSExpression(forConstantValue: firstValue.doubleValue)
return NSExpression(forFunction: function, arguments: [newFirst, last])
} else {
return self
}
}
}

I think You need to User DDMathParser Which is best in this situation. I have used it in One of my project which is facing same problem as you have faced
DDMathEvaluator *eval = [DDMathEvaluator defaultMathEvaluator];
id value=[eval evaluateString:#"1/2" withSubstitutions:nil error:&error];
NSLog(#"Result %#",value);
Result 0.5

Rickster's solution worked, but had problems with expressions like 5*5/2, where the first argument (here 5*5) was not just a number.
I found a different solution here that works for me: https://stackoverflow.com/a/46554342/6385925

for people who still have this problem i did a somewhat quick fix:
extension String {
var mathExpression: String {
var returnValue = ""
for value in newString.components(separatedBy: " ") {
if value.isOperator {
returnValue += value
} else {
returnValue += "\(Double(value) ?? 0)"
}
}
return returnValue
}
var isOperator: Bool {
["+", "-", "/", "x", "*"].contains(self)
}
}

Related

Convert a string into a int

I need some help here, I am currently making a game, but I got stuck somewhere. So, what I want is, if a Labels text is higher then the other labels text, then something will happen, I typed If Label26.Text > Label24.Text Then Label33.Visible = True which seems not to work, please, I need some help here, thanks. And yes, the labels text is NUMBERS.
The Text property of a label is a string. As far as computers go, you can't do math (using comparison operators like > will not return the result you are expecting) with strings because they are just a sequence of characters.
Even if the string only contains a number, the computer still sees it as a sequence of characters and not a number ("5" is a string literal with the character 5 in it, while 5 is an integer that can be used in a mathematic expression).
As some of the other commenters mentioned, you need to cast the Text property to an Integer or Double (or some other numeric data type). To do so, you'd want to use Int32.Parse to change the strings to integers.
If Int32.Parse(Label26.Text) > Int32.Parse(Label24.Text) Then Label33.Visible = True
You can use the int.tryParse to check if the content of the variable is a number or not. The output of the TryParse is a boolean, see the example below:
int num1 = 0;
bool num1_ = false;
num1_ = int.TryParse(txt1.Text.ToString(), out num1);
if (num1_)
{
// Is a number/integer
//Do something
}
else
{
//Is a string
//Do something else
}

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.

if statement comparing integers not working in objective c

I am trying to perform logic based on the values of two integers. Here I am defining my integers, and I also have NSLog so I can see if the values are correct when I run the code:
int theHikeFlag = (int)[theNewHikeFlag objectAtIndex:(theID-1)];
NSLog(#"theHikeFlag: %#",theHikeFlag);
int fromTheDB = [self.detailItem hikeFlag];
NSLog(#"fromTheDB: %d",fromTheDB);
And here is the logic:
if (theHikeFlag==1) {
hikeString=#"You have";
}
else if (theHikeFlag==0) {
hikeString=#"You have not";
}
else {
if (fromTheDB==1) {
hikeString=#"You have";
}
else {
hikeString=#"You have not";
}
}
As an example of how this code is working. When theHikeFlag=1 and fromTheDB=0, the code bypasses the if and the else if and goes straight to the else and sets hikeString="You have not". This means that my result is irrelevant of theHikeFlag and is based on the fromTheDB integer.
Since you cannot store ints in an array, the line
(int)[theNewHikeFlag objectAtIndex:(theID-1)];
is not doing what you think it should. You need to pull the data from NSNumber, not cast to int.
int theHikeFlag = [[theNewHikeFlag objectAtIndex:(theID-1)] intValue];
The reason why the log output is correct is a bit funny: you made two mistakes in a row! First, you re-interpreted a pointer as an int, and then you let NSLog re-interpret it as an object again by adding a format specifier %# that is incompatible with int, but works fine with pointers! Since the int value contains a pointer to NSNumber, NSLog produces the "correct" output.

Converting uppercase string to title case in Objective-C

I created the following method which starts by using the built-in convertStringToTitleCase method on NSString but it really just capitalizes the first letter of each word. I see in .NET there is a method for TextInfo.ToTitleCase which attempts what I'd like to do with Objective-C but also falls short.
http://msdn.microsoft.com/en-us/library/system.globalization.textinfo.totitlecase.aspx
The method I wrote to start is below. How would you handle properly casing an uppercase string? Would a database of words to convert to all uppercase/lowercase help?
- (NSString *)convertStringToTitleCase:(NSString *)str {
NSMutableString *convertedStr = [NSMutableString stringWithString:[str capitalizedString]];
NSRange range = NSMakeRange(0, convertedStr.length);
// a list of words to always make lowercase could be placed here
[convertedStr replaceOccurrencesOfString:#" De "
withString:#" de "
options:NSLiteralSearch
range:range];
// a list of words to always make uppercase could be placed here
[convertedStr replaceOccurrencesOfString:#" Tv "
withString:#" TV "
options:NSLiteralSearch
range:range];
return convertedStr;
}
As noted in comments, the .NET method you refer to doesn't do "proper" title case (that is, follow a list of exception words to be left in either all-caps or all-lowercase), so -[NSString capitalizedString] is as equivalent as you'll get. If you want exception words, you'll have to write your own method (or find someone else who did, as a google search for NSString "title case" might).
How "proper" your title casing gets depends on how many exception words you're willing to throw at it. How much of the English language do you want it to support? What about other languages? It'll also depend on how far you go in analyzing word boundaries -- you might want "TV" to stay all-caps regardless of whether it's in quotes, at the end of a sentence, etc., but you probably also don't want "you've" to come out "You'Ve".
If you want to process exception words, your plan of repeatedly running replaceOccurrencesOfString... will get slower the more exception words you have. (Also, using spaces in your search/replace strings means you aren't considering other word boundaries you might want to.)
It might be useful to consider NSRegularExpression, since regular expressions already have pretty robust notions of case and word boundaries. If that doesn't work well for you, using a scanner to read through the input string while producing a transformed output string would be more efficient than running multiple search/replace operations.
A nice one-liner(not a general solution, probably very inefficient on huge strings):
[[str lowercaseString] capitalizedString];
extension String {
/**
Get the title case string.
*/
var titleCase: String {
get {
return getTitleCaseString()
}
}
// MARK: Private methods.
/**
Get title case string.
- returns: The title case string regarding the lowercase words.
*/
private func getTitleCaseString() -> String {
struct Holder {
static let lowercaseWords = ["a", "an", "and", "at", "but", "by", "else", "for",
"from", "if", "in", "into", "is", "nor", "of", "off",
"on", "or", "out", "the", "to", "via", "vs", "with"]
}
return replaceToLowercaseAllOccurrencesOfWords(Holder.lowercaseWords).capitalizeFirst
}
/**
Replace to lowercase all occurrences of lowercase words.
- parameter lowercaseWords: The lowercase words to replace.
- returns: String with all occurrences replace to the lowercase words.
*/
private func replaceToLowercaseAllOccurrencesOfWords(lowercaseWords: [String]) -> String {
let capitalizedSelf = NSMutableString(string: self.capitalizedString)
for word in lowercaseWords {
if let lowercaseWordRegex = try? NSRegularExpression(pattern: "\\b\(word)\\b", options: .CaseInsensitive) {
lowercaseWordRegex.replaceMatchesInString(capitalizedSelf,
options: NSMatchingOptions(),
range: NSMakeRange(0, capitalizedSelf.length),
withTemplate: word)
}
}
return capitalizedSelf as String
}
/**
Capitalize first char.
*/
private var capitalizeFirst: String {
if isEmpty { return "" }
var result = self
result.replaceRange(startIndex...startIndex, with: String(self[startIndex]).uppercaseString)
return result
}
}

"used struct type value where scalar is required" at .layer.position

I want to make a selection before apply one of two animations,
what I thought is: make a Point one, if my myImageView is at the Point one, then apply animationNo1, else apply animationNo2, but I got this:"used struct type value where scalar is required", at line if (myImageView.layer.position = one)
What I do? how can I fix this?
Does anyone know exactly what makes the problem happen?
CGPoint one = CGPointMake(myImageView.layer.position.x, 100);
if (myImageView.layer.position = one)
{
animationNo1
}
else
{
animationNo2
}
First of all, your if-statement will not do what you think. If you want to compare something you have to use == (ie 2 =)
and you can't compare CGPoints like this.
use
if (CGPointEqualToPoint(one, self.view.layer.position))
if (myImageView.layer.position = one) { animationNo1 }
should be
if (CGPointIsEqualToPoint(myImageView.layer.position, one)) { animationNo1 }
You used a single = meaning assignment, rather than a == for comparison. But the == wouldn't do what you wanted here anyway.
You are passing a struct (int this case position) instead of a scalar. To do what you want you need to use CGPointIsEqualToPoint:
if (CGPointEqualToPoint(one, self.view.layer.position))
Full code with corrections:
CGPoint one = CGPointMake(myImageView.layer.position.x, 100);
if (CGPointEqualToPoint(one, self.view.layer.position))
{
animationNo1
}
else
{
animationNo2
}
Also, as others have pointed out: Be careful about = vs ==. They are different. In this case you don't use == for comparison fortunately, but if you use = for other stuff it will make it true instead of checking to see if it is true.