Calvin hates his Homework

Calvin hates his homework so.
He knows more than his teacher knows.
His wicked teacher has assigned
ten-thousand problems , wastes of time.
"I'll learn nothing from this homework, bah!"
"It's only simple algebra."
"Screw homework" , cries Calvin, "My teacher is crazy."
"Calvin needs time to spend with the ladies."
Thankfully his computer skills wreck.
What is the sum of all values of x x ?

Details and assumptions :

  • The problems can be found here .

  • Round the total to the tenth's place.

  • The operators that can be used include {+, -, *, =}.

  • No problems with multiple values of x x exist.

Images belong to Bill Watterson . No copyright infringement intended.


The answer is 2328.1.

This section requires Javascript.
You are seeing this because something didn't load right. We suggest you, (a) try refreshing the page, (b) enabling javascript if it is disabled on your browser and, finally, (c) loading the non-javascript version of this page . We're sorry about the hassle.

12 solutions

My solution in C++:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <bits/stdc++.h>
using namespace std;

double resolver(string str){
    int lineales = 0;
    int constantes = 0;
    int signo_lado = 1;
    int signo_termino = 1;
    int valor_actual = 0;
    for(int i=0;i<str.size();i++){
        char actual = str[i];
        if(actual=='+'){
            constantes -= valor_actual*signo_lado*signo_termino;
            signo_termino = 1;
            valor_actual = 0;
        }else if(actual=='-'){
            constantes -= valor_actual*signo_lado*signo_termino;
            signo_termino = -1;
            valor_actual = 0;
        }else if(actual=='='){
            constantes -= valor_actual*signo_lado*signo_termino;
            signo_lado = -1;
            signo_termino = 1;
            valor_actual = 0;
        }else if(actual=='*'){
            lineales += valor_actual*signo_lado*signo_termino;
            valor_actual = 0;
            i++;
        }else if(actual=='x'){
            lineales += signo_lado*signo_termino;
            valor_actual = 0;
        }else if(actual=='0' || actual=='1' || actual=='2' || actual=='3' || actual=='4' || actual=='5' || actual=='6' || actual=='7' || actual=='8' || actual=='9'){
            int digito = atoi(&actual);
            valor_actual = valor_actual*10 + digito;
        }
    }
    constantes -= valor_actual*signo_lado*signo_termino;
    return double(constantes)/double(lineales);
}

int main()
{
    ifstream archivo("problems.txt");
    string ecuacion;
    double ans = 0;
    while(getline(archivo, ecuacion)){
        ans += resolver(ecuacion);
    }
    cout << ans;
    return 0;
}

Output: 2328.11 \boxed{2328.11}

Basically I parse all the possible symbols, then I save the coefficients of x x in a variable and I save all the linear terms in another variable. At the end, my equation is of the form a x = b ax=b , so the answer is b a \dfrac{b}{a} .

That is very good. You worked really hard

Agnishom Chattopadhyay - 5 years, 12 months ago

How do you get syntax highlighting?

Manjunath Sreedaran - 5 years, 12 months ago

Log in to reply

Just use this:

```[your language here]

[your code here]

```

Note that the marks used are ` ( grave accents ) and not ' ( apostrophes ).

Brock Brown - 5 years, 12 months ago

Log in to reply

This is a great question! Please post a question with 100 variables-100 equations, that would be amazing.

Archit Boobna - 5 years, 11 months ago

Thank you!

Manjunath Sreedaran - 5 years, 12 months ago

Log in to reply

@Manjunath Sreedaran No problem. :)

Brock Brown - 5 years, 12 months ago

the code won´t work, that's an ArrayList and you cast it as [i], you need to use .get(i)

Yop Me again - 5 years, 8 months ago

[This is not a solution. Just clever use of Computer Algebra Systems]

sage sage Code:

1
2
3
4
f = open("problems.txt").read().replace("=","==").split("\n")
for equation in f[:len(f)-1]:
    arr.append(solve(eval(equation),[x])[0].rhs())
sum(map(float, arr))

You can run Sage without downloading anything at http://sagecell.sagemath.org/

[The real solution can be very hard to code. It will require a good knowledge of parsing expressions among other harder things]

Moderator note:

What concise code.

Arulx Z
Jul 11, 2015

My solution might be hard to interpret, so here's what actually happening -

Note - LHS = Left Hand Side and RHS = Right Hand Side

First I separate LHS and RHS of the equation. Then I separate the variable and constant terms. Since we only care about coefficients of the variables, we only retain them while dispose off the variable.

Then I subtract variables on RHS from LHS. Then I subtract the constants on LHS from RHS. Then I divide the result obtained from constant subtraction with the result obtained from variable subtraction.

Here is my code -

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
>>> def sep(exp):
        cont = False
        samp = uv = uc = optr = ''
        for x in exp:
            if cont:
                cont = False
                continue
            if x == '+' or x == '-':
                if 'x' in samp:
                    uv += optr + '1'
                else:
                    uc += samp
                optr = x
                samp = ''
            elif x == '*':
                uv += samp
                cont = True
                samp = ''
                continue
            samp += x
        if 'x' in samp:
            uv += optr + '1'
        else:
            uc += samp
        return uv, uc
>>> def evl(lc):
        samp = ''
        asd = 0
        for x in lc:
            if x == '+' or x == '-':
                asd += int(samp) if samp != '' else 0
                samp = ''
            samp += x
        return asd + int(samp) if samp != '' else 0
>>> tots = 0
>>> with open('problems.txt', 'r') as f:
        for line in f:
            n = line.replace(' ', '')
            arr = n.split('=', 1)
            l = arr[0]
            r = arr[1]
            d1 = sep(l)
            d2 = sep(r)
            tots += -1 * float(evl(d1[1]) - evl(d2[1]))/float(evl(d1[0]) - evl(d2[0]))
>>> print tots
2328.10576214

My longest python code ever written (and possibly the ugliest). Now wait until I invent new WolframAlpha.

Each line must be reduced to a single numerical result; all line results must be collapsed into a sum for the final solution.

Using Python, I convert each line/equation to the form: α x + c = 0 \alpha x + c = 0 by grouping like terms in order to count coefficients for all x x and 1 1 ( unit ) terms. My code is "ugly" with debugging statements purposely left in to show work (for the reader's understanding besides the code comments), and with verbose calculations/inelegant constructs to divulge my mental deconstruction of the problem.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
fileName = 'problems.txt' # change to point to sample file
printFlag = False # like #ifdef DEBUG

xSolutions = [] #keeps 'x' value of each solved line

# Reduces a string of terms to a count of x's and units
# When solving for x, negates units count (to simulate moving across equal sign)
def countTerms(line):
  xCount = 0
  unitCount = 0
  if (printFlag):
    print('before counting: ' + line)
  terms = line.split('+')
  if (printFlag):
    print("terms: " + str(terms))
  for term in terms:
    if (term == 'x'):
      xCount += 1;
    elif ('*x' in term):
      xCount += int(term.replace('*x', ''))
    else:
      unitCount += int(term)
  if (printFlag):
    print('xCount: ' + str(xCount) + "; unitCount: " + str(unitCount))
    print('xSolution: ' + str((-unitCount)/xCount))
    print()
  xSolutions.append((-unitCount) / xCount)

# Swaps numerical signs for a given expression
# Inserts coefficent of -1 at simple subtractions (for ease of counting above)
def swapSigns(line):
  result = ''
  for i in range(len(line)):
    if (line[i] == '+'):
      result += '+-'
    elif (line[i] == '-'):
      result += '+'
    else:
      result += line[i]

  # insert coefficients for convenience
  result = result.replace('+-x', '+-1*x')
  if (printFlag):
    print('swapSigns('+ line +'): ' + result)

  return result

# MAIN LOOP over problem file contents
with open(fileName, 'r') as f:
  for line in f:
    line = line.strip().replace(' ', '')

    line = line.replace('=', '=+')
    line = line.split('=')
    lhs = line[0].replace('-x', '+-1*x') # insert coefficients for convenience
    rhs = line[1]
    rhs = swapSigns(rhs)

    line = lhs + rhs

    countTerms(line) #puts counts in console, solutions in xSolutions

# DISPLAY SOLUTION sum of 'x' values
if (printFlag):
  print(xSolutions)
total = 0
for x in xSolutions:
  total += x
print(total) 

Abdelhamid Saadi
Jun 22, 2015

This solution in python works because all the equations are linear with one variable:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
def root(equa):
    [left, right] = equa.split("=")
    x = 0
    b = eval(left) -eval(right)
    x = 1
    a = eval(left) -eval(right) - b
    return -b/a

def resolve():
    tot = 0
    for equa in open('problems.txt', 'r').read().split("\n"):
        if "=" in equa:
            tot += root(equa)   
    return tot

Dpk ­
Jun 18, 2015

It's probably easier using python math libraries like sympy, but here's my solution using python's standard libraries. Basically I do some string manipulations and use the eval() function to try to find the solution using binomial search

f = open('problems.txt', 'r')
lines = [x.strip() for x in f.readlines()]

def root(eq, a, b):
    x = b
    if eval(eq) < 0:
        return root(eq,b,a)
    x = (a+b)/2.0

    #raw_input(eval(eq))
    if (-1.0e-16 <= eval(eq) <= 1.0e-10):
        return x
    elif (eval(eq) > 0):
        return root(eq, a, x)
    else:
        return root(eq, x, b)

def solve(eq):
    eq = eq.split('=')
    left = '(' + eq[0] + ')'
    right = '(' + eq[1] + ')'
    return root(left + '-' + right, 1.0e10, -1.0e10)

total_x = 0.0
for i, val in enumerate(lines):
    sol = solve(val)
    #print i, sol
    total_x += sol

print total_x
Bill Bell
Jan 9, 2016

Two solutions

First solution: Convert the equations into expressions involving complex numbers so that they can be simplified using Python's built-in eval function. For example, the first problem converts from x = 42*x + 85 - 71 to 1j-42j-85+71 (the 'j' being Python's 'i'). The real and imaginary parts of the result of this expression can be used to form a fraction enabling precise calculation of the total required for solution of the problem. Here's the complete script.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from fractions import Fraction

total=Fraction(0)
for line in file('problems.txt').readlines():
    problem=line[:-1].replace(' ','').replace('*x','j').replace('x','1j')
    problem=list(problem)
    p=problem.index('=')
    if not problem[p+1] in ['+','-']:
        problem[p]='+'
    else:
        problem.remove('=')
    for i in range(p,len(problem)):
        if problem[i]=='+':
           problem[i]='-'
        elif problem[i]=='-':
                problem[i]='+'
        else:
            pass
    problem=''.join(problem)
    asComplex=eval(problem)
    total+=Fraction(int(asComplex.real),-int(asComplex.imag))

print 1.*total    

Second solution: Just use sympy. Read each equation, convert it to an expression acceptable to sympy and solve it.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from sympy import *
var('x')

total=0
for line in file('problems.txt').readlines():
    problem=line[:-1].replace('=','-(')+')'
    print problem
    solution=solve(sympify(problem))
    if type(solution)==list:
        solution=solution[0]
    total+=solution

print N(total)   

Akash Gaonkar
Jun 24, 2015

I used a few tricks to make the problem easier, then solved it. My solution hinges on the idea that we only need to worry about addition, subtraction, and multiplication (which can be resolved in that order), and that there are no cases of one constant times another constant (so we don't even need to worry about multiplication if no 'x' is present.)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
def main():
    lines = open('problems.txt').read().splitlines()

    total = 0
    for line in lines:
        soln = solve_for_x(line)
        total += soln
        print(soln)

    print("Total:", total)

def solve_for_x(line):
    lhs, rhs = line.replace(" ", "").split("=")
    xpr = to_xpression(lhs) - to_xpression(rhs)
    return xpr.solve_for_x()

def to_xpression(string):
    xpr = Xpression()

    added = string.split("+")
    for a in added:
        subtracted = a.split("-")
        #the first item is an addition
        xpr += parse_piece(subtracted.pop(0))
        for b in subtracted:
            xpr -= parse_piece(b)

    return xpr

def parse_piece(string):
    if string == 'x': return Xpression(1)
    elif 'x' in string:
        xcoeff = string.split("*")[0]
        return Xpression(float(xcoeff))
    else: return float(string)

class Xpression:

    def __init__(self, xcoeff=0, const=0):
        self.xcoeff = xcoeff
        self.const = const

    def solve_for_x(self):
        return -self.const / self.xcoeff;

    def __add__(self, other):
        if isinstance(other, Xpression):
            return Xpression(self.xcoeff + other.xcoeff, self.const + other.const)
        elif isinstance(other, (int, float)):
            return Xpression(self.xcoeff, self.const + other)
        else: raise "Error: cannot add Xpression and "+str(type(other))+"."

    def __sub__(self, other):
        if isinstance(other, Xpression):
            return Xpression(self.xcoeff - other.xcoeff, self.const - other.const)
        elif isinstance(other, (int, float)):
            return Xpression(self.xcoeff, self.const - other)
        else: raise "Error: cannot subtract Xpression and "+str(type(other))+"."        

    def __mul__(self, other):
        if isinstance(other, (int, float)):
            return Xpression(self.xcoeff * other, self.const * other)
        else: raise "Error: cannot multiply Xpression and "+str(type(other))+"."

    def __str__(self):
        return str(self.xcoeff) + "x + " + str(self.const)

main()

Brian Riccardi
Jun 20, 2015

Here's mine c/c++ solution! :)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include<bits/stdc++.h>
using namespace std;

ifstream in("problems.txt");

//takes out the spaces
void pre_parsing(char* s)
{
    in.getline(s,50);
    int len=strlen(s), y=0;
    for(int x=0; x<len; ++x){
        s[y]=s[x];
        if(s[x]!=' ') ++y;
    }
    s[y]='\0';
}

//solves an equation
long double solve(char* s)
{
    long double coeff_x=0,
        coeff_0=0,
        temp_n,
        len=strlen(s);
    bool sum=true,
         left=true;

    for(int x=0; x<len; ++x){
        temp_n=0;
        if(s[x]=='='){
            sum=true;
            left=false;
            continue;
        }
        if(s[x]=='+'){
            sum=true;
            continue;
        }
        if(s[x]=='-'){
            sum=false;
            continue;
        }
        if(s[x]<='9' && s[x]>='0'){
            while(s[x]<='9' && s[x]>='0')
                temp_n=temp_n*10+s[x++]-'0';
            if(s[x]!='*'){ coeff_0+=(left^sum)? temp_n:-temp_n; --x; }
            else{ coeff_x+=(left^sum)? -temp_n:temp_n; ++x; }
        }
        else if(s[x]=='x') coeff_x+=(left^sum)? -1:1;
    }

    return coeff_0 / coeff_x;
}

int main()
{
    cout.precision(15);
    char s[50];
    long double ans=0;
    for(int x=0; x<10000; ++x){
        pre_parsing(s);
        ans+=solve(s);
    }

    cout << ans << "\n";

    return 0;
}

Gaurav Rao
Jun 19, 2015

My solution in C (and in english)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
        double xterm;
        double constterm;
}expression;
typedef struct {
        expression *left;
        expression *right;



} equation;


expression *createExpression(char *str, int len){
        expression* e = (expression *) malloc(sizeof(expression));

        e->xterm =0;
        e->constterm =0;
        int isX = 0;
        int number = 0;
        int i;
        int sign = 1;
        for(i=0; i < len; i++){
                if(*(str +i) == '+'){
                        if(isX){
                                e->xterm += number*sign;
                        }else{
                                e->constterm += number * sign;
                        }
                        isX =0;
                        number = 0;
                        sign = 1;

                }
                else if(*(str + i) == '-'){
                        if(isX){
                                e->xterm += number * sign;
                        }else{
                                e->constterm += number * sign;
                        }
                        isX =0;
                        number = 0;
                        sign = -1;
                }
                else if(*(str +i) == 'x'){
                        isX = 1;
                        number = (number ==0)?1:number;
                }
                else if(*(str +i)>= '0' && *(str +i) <='9'){
                        number= number * 10 + *(str +i) - '0';
                }

        }
        if(isX){
                e->xterm += number * sign;

        }       else
                e-> constterm += number * sign;
        return e;
}
equation *createEquation(char*str, int len){
//      printf("creating equation...\n");
//      printf("the passed string was %s.\n",str);
        int equalsIndex;
        int i;
        for(i=0;i<len;i++){
                if(*(str+i)=='='){
                        printf("%c",*(str+i));
                        equalsIndex = i;
                }
        }
//      printf("the equals is at %d\n",equalsIndex);
        equation *eq = (equation *)malloc(sizeof(equation));
        eq->left = createExpression(str,equalsIndex);
        eq->right = createExpression(str + 1 + equalsIndex, len - equalsIndex - 1);
        return eq;
}
double solveEquation(equation *eq){
        return (eq->right->constterm - eq->left->constterm)/(eq->left->xterm-eq->right->xterm);
}
int main(int argc, char ** argv)
{
        int counter =1;
        double tot =0;
        equation *eq;
//      printf("Creating string\n");
        char* str = (char *)malloc(100*sizeof(char));
//      printf("String initialized\n");

        while(fgets(str,100,stdin)!=NULL){
                counter ++;
                eq = createEquation(str,strlen(str));
                printf("%fx + %f = %fx + %f\n",eq->left->xterm,eq->left->constterm,eq->right->xterm,eq->right->constterm);
                printf("\n%f\n", solveEquation(eq));
                tot += solveEquation(eq);

        }
        printf("%f\n%d\n",tot,counter);
        return 0;
}

Last line of the output is the solution. Pipe in the input file using > in your command line.

Joshua Houle
Jun 17, 2015

My solution is almost identical to another solution already posted, but I will post mine anyways. I am using python 2.7 and installed sympy.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from sympy import solve
from sympy import Symbol

x = Symbol('x')

problems = open('problems.txt','r').read().split('\n')
problems = [p.split("=")[0]+"-("+p.split("=")[1]+")" for p in problems]

theSum = 0
for problem in problems:
     theSum += solve(problem,x)[0]
print round(float(theSum),1) 

Brock Brown
Jun 16, 2015

Python 2.7:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from sympy.solvers import solve
from sympy import Symbol
x = Symbol('x')
total = 0
for problem in open("problems.txt", 'r'):
    # make an expression that's equal to zero
    problem = problem.split("=")
    problem = problem[0] + '-(' + problem[1] + ')'
    total += solve(eval(problem), x)[0]
print "Answer:", round(float(total),1)

Dependencies:

Sympy (if you're on Linux: sudo pip install sympy)

Note: initially, I made a solution that used bisection search , but the answer was actually off by two due to a weird precision error. :-\ So you get bonus points if you can figure that out!

Can you post your bisection search code?

Arulx Z - 5 years, 11 months ago

Log in to reply

I think I deleted it at some point, I'll rewrite it and post it when I get back from work in a few hours.

Brock Brown - 5 years, 11 months ago

how do you paste python code with syntax highlighting?

DPK ­ - 5 years, 12 months ago

Log in to reply

Just use this:

```[your language here]

[your code here]

```

Note that the marks used are ` ( grave accents ) and not ' ( apostrophes ).

Brock Brown - 5 years, 12 months ago

How did you generate the list of equations?

Agnishom Chattopadhyay - 5 years, 12 months ago

Log in to reply

I made a list of empty equations like this...

1
2
3
4
5
structures = (\
    "12 + {0} = {1}*x",
    "{0}*x+{0}*x = {1},
    "42{0} - x + x -x = {1}",
    "55 * 2 * {0} = x + 2*x*{1}")

And to make a random problem, I formatted some random integers in:

1
2
from random import choice, randint
problem = choice(structures).format(randint(1, 100), randint(1, 100))

Brock Brown - 5 years, 12 months ago

Log in to reply

Interesting. Another approach could be using a formal grammar.

I agree that this is a big fat waste of Calvin's time. In reality, there are many many teachers who are actually putting ton's of homework of stuff that dhould be done by a computer. Instead of calculation, we should be teaching our students numerical methods and how to use a computer

Agnishom Chattopadhyay - 5 years, 12 months ago

Log in to reply

@Agnishom Chattopadhyay Agreed, wholeheartedly.

Let me know if you ever write a program that manipulates formal grammar, I'd love to read it!

Brock Brown - 5 years, 12 months ago

@Agnishom Chattopadhyay Great response, bro

Ashish Menon - 5 years, 4 months ago

0 pending reports

×

Problem Loading...

Note Loading...

Set Loading...