PHP Code:
//Beginner Programming Challenge #11
#include <stdio.h> //standard for i/o
#include <stdlib.h> // standard again
#include <string.h> // string library
#include <math.h> // for the power function
int i,true=2,k[99],is,is2,w,iv,si,dubios,nc,number,zero,neo,num[99];
/*
i is standard
true is something that is always true since i don't know the c version of "while true"
is is the empty spaces in the string counter
is2 is the 'how much till the end' counter
w is like a secondary i
si counts how many words are between two spaces since operators can only use one space
dubios seeks dubious behaviour
nc is the number counter
number is the temporary number
zero alerts if someone wants to divide by 0
neo is the not enough operators counter
num is the number array
*/
char x[100];
//the string
float n_to_f;
// for the dubious output
int main(){
while (true){
for (i=0;i<99;++i) num[i]=k[i]=0; // reset the arrays
i=is=is2=w=iv=si=dubios=nc=zero=neo=number=0; // reset the variables
printf("> ");
gets(x);
if (strcmp(x,"exit")== 0) break;
for (i=0;i<strlen(x);++i){ //find empty spaces and keep track of them in k
if (x[i]==' ') {
k[is] = i;
++is;
}
}
if (k[is] != strlen(x)) {k[is]=strlen(x);++is;} // add to the counter the last element
iv=0;// needed later on
for (w=0;w<is;++w){ // for all the empty spaces
is2=k[w]-iv; //how many characters does the string fragment have
number=0; //reset the number
for (i=iv;i<k[w];++i){ //figure out what the number is
si=is2;
switch(x[i]){
case '0'...'9': number += ((x[i] - '0') * pow( 10.0 , is2-1));
--is2 ;
if (is2==0) { //when is reaches 0 save the number
num[nc]=number;
++nc;
}
break;
case '+': if (si==1){
if(nc>1){
num[nc-2]=num[nc-2]+num[nc-1];
num[nc-1]=num[nc];
--nc;
}
else ++neo;
}
else ++dubios;break;
case '-': if (si==1){
if(nc>1){
num[nc-2]=num[nc-2]-num[nc-1];
num[nc-1]=num[nc];
--nc;
}
else ++neo;
}
else ++dubios;break;
case '/': if (si==1){
if(nc>1){
if (num[nc-1]!=0){
num[nc-2]=num[nc-2]/num[nc-1];
num[nc-1]=num[nc];
--nc;
}
else ++zero;
}
else ++neo;
}
else ++dubios;break;
case '*': if (si==1){
if(nc>1){
num[nc-2]=num[nc-2]*num[nc-1];
num[nc-1]=num[nc];
--nc;
}
else ++neo;
}
else ++dubios;break;
case '^': if (si==1){
if(nc>1){
num[nc-2]=pow(num[nc-2],num[nc-1]);
num[nc-1]=num[nc];
--nc;
}
else ++neo;
}
else ++dubios;break;
case '%': if (si==1){
if(nc>1){
num[nc-2]=num[nc-2]%num[nc-1];
num[nc-1]=num[nc];
--nc;
}
else ++neo;
}
else ++dubios;break;
//for all cases of operands if the string fragment is wider than 1 caracter mark it as dubious behavior and if you dont have at least 2 operands mark it down
default: ++dubios;break;
//anything else goes to dubious behaviour
}
}
iv=k[w];//we need this to find out the word size
++iv;
}
n_to_f=num[nc-1];//transform it to float because thats what the post asks for
if (dubios==0){//if nothing is dubious ... this should be obvious
if (zero!=0) printf("Divided by Zero\n");
else if (neo>0) printf("Not enough operands\n");
else if (neo==0 &&nc>1) printf("Too many operands\n");
else if (nc==0); //if empty string
else printf("%.1f\n",n_to_f); }// if everything goes to plan print the number
else printf("Unrecognized token\n");
}
return 0;
}
Last edited by tooatw; March 29th, 2010 at 05:06 PM.
Well, it's more a matter of too many indents, that's why I suggested breaking up the code into smaller pieces (functions), it'll make the code more readable and cut down on the number of variables needed.
For example the whole operator handling could be stored in a separate function:
Some people prefer to line up their cases with the switch statement, but that's just a matter of taste, as long as you're consistent.Code:int eval_operator(int operator, int operand1, int operand2) { int result; switch (operator) { case '+': /* TODO: catch overflow before it happens */ result = operand1 + operand2; break; case '-': result = operand1 - operand2; break; ... default: fprintf(stderr, "unsupported operator '%c'!\n", operator); result = SOME_ERROR_CODE; break; } return result; }
Oh, and never use gets(), it's a buffer overflow waiting to happen, use fgets():
Code:fgets(x, 100, stdin);
Last edited by Compyx; March 29th, 2010 at 05:40 PM. Reason: add suggestion about fgets()
Is it just me, or are these Beginner challenges more likely suited for the intermediate challenges?
Support 7z in default installs!!!: Click Here
How to use code blocks to post command output: Click Here
Official Ubuntu Documentation
RPN is actually pretty simple to deal with. Every token is whitespace delimited, and evaluation can be implemented easily with a stack. The extra (extra) credit, though, it probably above beginner level - hence it's optional. These are supposed to be challenges, after all.
Posting code? Use the [code] or [php] tags.
I don't care, I'm still free. You can't take the sky from me.
i'm a beginner
originally i wanted to get the elements with %s but i dropped it for some reason
like
while (1)
scanf("%s",x)
and take every s separately with the same switch that i have now
there are many ways that a beginner can think of
just for the record, the first time i ever implemented something was about 3 months ago and i failed miserably
i only started programming for the past 2-3 weeks
Infix to postfix isn't that hard either, and it too can be implemented using a stack (and a queue).
The algorithm is a bit more complex than a postfix calculator, and increases when adding unary/ternary operators and function-calls.
My python entry (now works for every input)
Output:PHP Code:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from sys import exit
import math
class Stack (object): # stack class, allows pushing, popping
def __init__(self): #+ could be used somewhere else ;)
self.stack = []
def push(self, val):
self.stack = [val] + self.stack
def pop(self):
val = self.stack[0]
self.stack.remove(self.stack[0])
return val
def __str__(self): # for the print stack bit below
if(self.stack[0] % 1 == 0):
return str(int(self.stack[0])) # if the number was whole
return str(self.stack[0]) # else
def main():
ans = 0
print "Everything must be spaced seperated"
while True:
stack = Stack()
try:
string = raw_input("Enter your sum: ")
except:
exit()
if(string == ""):
pass
elif(string != "Q"):
split = string.split(" ")
for token in split:
try:
if(token == "+"):
stack.push(stack.pop()+stack.pop())
elif(token == "-"):
a = stack.pop()
b = stack.pop()
stack.push(b - a)
elif(token == "*"):
stack.push(stack.pop()*stack.pop())
elif(token == "/"):
a = float(stack.pop())
if(a == 0):
print "Divide by 0 error"
continue
b = float(stack.pop())
stack.push(b / a)
elif(token == "%"):
a = float(stack.pop())
b = float(stack.pop())
stack.push(b % a)
elif(token == "^"):
a = float(stack.pop())
b = float(stack.pop())
stack.push(b ** a)
elif(token == "ans"):
stack.push(ans)
elif(token == "sqrt"):
stack.push(math.sqrt(stack.pop()))
elif(token == "cos"):
stack.push(math.cos(stack.pop()))
elif(token == "sin"):
stack.push(math.sin(stack.pop()))
elif(token == "fact"):
stack.push(math.factorial(stack.pop()))
elif(token == "pi"):
stack.push(math.pi)
else:
stack.push(int(token))
except Exception as e: # if there was an error
print stack.stack #+ its probably the input
print "Error in input: " + str(e)
exit()
print stack # print result
ans = stack.stack[0] # for recall later
else:
exit() # if it is Q to quit, quit
if __name__ == '__main__':
main()
Code:matthew@matthew-desktop:~/Documents/Programming/Python$ python reverse_polish.py Everything must be spaced seperated Enter your sum: 3 4 - 5 + 4 Enter your sum: 3 4 5 * - -17 Enter your sum: 5 1 2 + 4 * + 3 -# [3, 17] Error in input: invalid literal for int() with base 10: '-#' matthew@matthew-desktop:~/Documents/Programming/Python$ python reverse_polish.py Everything must be spaced seperated Enter your sum: 5 2 ^ 25 Enter your sum: 10 5 % 0 Enter your sum: 10 3 / 3.333333333333333 Enter your sum: 10 0 / Divide by 0 error 10 Enter your sum: 10 sin -0.544021110889 Enter your sum: 10 cos -0.839071529076 Enter your sum: 10 sqrt 3.16227766017 Enter your sum: 10 fact 3628800 Enter your sum: pi 3.14159265359 Enter your sum: Q matthew@matthew-desktop:~/Documents/Programming/Python$
Last edited by matmatmat; March 31st, 2010 at 08:36 PM. Reason: watch as more and more useless things are added
Interesting point. I vaguely recall a related programming task coming up in one of the courses available to second-year students at the University I attended, but one I don't think I took that subject (too much partying? wrong course? it was a long tima ago). If memory serves correctly it was related to converting regular algebraic expressions to RPN (a.k.a. infix to postfix)
Forum DOs and DON'Ts
Please use CODE tags
Including your email address in a post is not recommended
My Blog
Bookmarks