简体   繁体   中英

Solving math equations with fractions on google scripts

I am making a Google Sheets program to create a math worksheet that randomly generates the numbers within certain parameters.

I have succeeded in addition, subtraction, a mix of addition and subtraction, and multiplication. I am now trying to add fractions to the mix, but have run into the formatting issue. While I have been able to generate random fractions and have them appear correctly, the issue comes in trying to have the correct answer generate on the Key sheet.

I have tried finding a way to read the cells occupied by fractions as a string and parse out the individual numbers however that would only solve the issue with the numerator, and I still have the issue with the denominator (finding the common one or at least having the answer one that can be simplified by the student or teacher after solved).

I included a link above, please let me know if you have any ideas to help with this issue.

Also since I don't think I have it properly documented in the script, the max value of integers generated is located on the key page in the range "K2"

function myWSG() {
 var ss = SpreadsheetApp.getActiveSpreadsheet();
 var ws = ss.getSheetByName("Worksheet");
 var ks = ss.getSheetByName("Key");

 var m = ks.getRange('K2').getValue()+1;

 function getRandomInt(min, max) {
 min = Math.ceil(min);
 max = Math.floor(max);
 return Math.floor(Math.random() * (max - min)) + min; //The maximum is exclusive and the minimum is inclusive
}
for (var i = 8; i <= 26; i = i + 2){
var num = getRandomInt(0, m);
var num1 = getRandomInt(0, m);
var dn1 = getRandomInt(0, m);
var dn2 = getRandomInt(0, m);
var sym = getRandomInt(0, 2);
ws.getRange("A1").copyFormatToRange(ws, 3, 3, i, i)
ws.getRange("A1").copyFormatToRange(ws, 5, 5, i, i)
 switch(ws.getRange(6, 5).getValue()){
  case "Fractions":
    ks.getRange("A6").setValue("Fractions");
    if(dn1 == 0){
      ws.getRange(i, 3).setValue(num)
    }
else if(dn1 == 1){
      ws.getRange(i, 3).setValue(num)
    }
    else{
      ws.getRange(i, 3).setValue(num + "/" + dn1);
    }
    if(dn2 == 0){
      ws.getRange(i, 5).setValue(num1)
    }
    else if(dn2 == 1){
      ws.getRange(i, 5).setValue(num1)
    }
    else{
      ws.getRange(i, 5).setValue(num1 + "/" + dn2);
    }
    break;
 case "Add&Sub":
    ks.getRange("A6").clearContent();
    if(num > num1){
      ws.getRange(i, 3).setValue(num);
      ws.getRange(i, 5).setValue(num1);
    }
    else{
      ws.getRange(i, 3).setValue(num1);
      ws.getRange(i, 5).setValue(num);
    }
    if(sym == 0){
      ws.getRange(i, 4).setValue('+')
     }
    else{
      ws.getRange(i, 4).setValue('-')
    }
    break;
  case "Addition":
    ks.getRange("A6").setValue("Fractions")
    ws.getRange(i, 4).setValue('+');
    if(num > num1){
      ws.getRange(i, 3).setValue(num);
      ws.getRange(i, 5).setValue(num1);
    }
    else{
      ws.getRange(i, 3).setValue(num1);
      ws.getRange(i, 5).setValue(num);
    }
    break;
  case "Subtraction":
    ks.getRange("A6").setValue("Fractions")
    ws.getRange(i, 4).setValue('-');
            if(num > num1){
      ws.getRange(i, 3).setValue(num);
      ws.getRange(i, 5).setValue(num1);
    }
    else{
      ws.getRange(i, 3).setValue(num1);
      ws.getRange(i, 5).setValue(num);
    }
    break;
  case "Multiplication":
    ks.getRange("A6").setValue("Fractions")
    ws.getRange(i, 4).setValue('x');
    ws.getRange(i, 3).setValue(num);
    ws.getRange(i, 5).setValue(num1);
    break;
 }
}
for (var v = 30; v <= 46; v = v + 3){
var vnum = getRandomInt(0, m); //random Integer 1
var vnum1 = getRandomInt(1, m); //random Integer 2
var vnum2 = getRandomInt(0, m); //random Integer 3
var vnum3 = getRandomInt(1, m); //random Integer 4
var vsym = getRandomInt(0, 2); //Symbol determinate
var vsym1 = getRandomInt(0, 2); //Symbol determinate 2
var vdn1 = getRandomInt(0, m); //random denominator 1
var vdn2 = getRandomInt(0, m); //random denominator 2
ws.getRange("A1").copyFormatToRange(ws, 3, 3, v, v); //Reset Format to 

ws.getRange("A1").copyFormatToRange(ws, 5, 5, v, v); //Reset Format to 

ws.getRange("N1").copyFormatToRange(ws, 3, 3, v+1, v+1); //Reset Format 

ws.getRange("N1").copyFormatToRange(ws, 5, 5, v+1, v+1); //Reset Format 

switch(ws.getRange(6, 5).getValue()){
  case "Fractions":
    if(vdn1 == 0){
      ws.getRange(v, 3).setValue(vnum);
    }
    else if(vdn1 == 1){
      ws.getRange(v, 3).setValue(vnum);
    }
    else{
      ws.getRange(v, 3).setValue(vnum + "/" + vdn1);
      ws.getRange(v, 5).setValue(vnum2 + "/" + vdn1);
    }
    if(vdn2 == 0){
      ws.getRange(v+1, 3).setValue(vnum1);
    }
    else if(vdn2 == 1){
      ws.getRange(v+1, 3).setValue(vnum1);
    }
    else{
      ws.getRange(v+1, 3).setValue(vnum1 + "/" + vdn2);
      ws.getRange(v+1, 5).setValue(vnum3 + "/" + vdn2);
    }
break;
  case "Add&Sub":
    if(vnum > vnum1){
      ws.getRange(v, 3).setValue(vnum);
      ws.getRange(v+1, 3).setValue(vnum1);
    }
    else{
      ws.getRange(v, 3).setValue(vnum1);
      ws.getRange(v+1, 3).setValue(vnum);
    }
    if(vnum2 > vnum3){
      ws.getRange(v, 5).setValue(vnum2);
      ws.getRange(v+1, 5).setValue(vnum3);
    }
    else{
      ws.getRange(v, 5).setValue(vnum3);
      ws.getRange(v+1, 5).setValue(vnum2);
    }
    if(vsym == 0){
      ws.getRange(v+1, 2).setValue('+');
    }
    else{
      ws.getRange(v+1, 2).setValue('-');
    }
    if(vsym1 == 0){
      ws.getRange(v+1, 4).setValue('-');
    }
    else{
      ws.getRange(v+1, 4).setValue('+');
    }
    break;
case "Addition":
    ws.getRange(v+1, 2).setValue('+');
    ws.getRange(v+1, 4).setValue('+');
    ws.getRange(v, 3).setValue(vnum);
    ws.getRange(v+1, 3).setValue(vnum1);
    ws.getRange(v, 5).setValue(vnum2);
    ws.getRange(v+1, 5).setValue(vnum3);
    break;
  case "Subtraction":
    ws.getRange(v+1, 2).setValue('-');
    ws.getRange(v+1, 4).setValue('-');
    if(vnum > vnum1){
      ws.getRange(v, 3).setValue(vnum);
      ws.getRange(v+1, 3).setValue(vnum1);
    }
    else{
      ws.getRange(v, 3).setValue(vnum1);
      ws.getRange(v+1, 3).setValue(vnum);
    }
    if(vnum2 > vnum3){
      ws.getRange(v, 5).setValue(vnum2);
      ws.getRange(v+1, 5).setValue(vnum3);
    }
    else{
      ws.getRange(v, 5).setValue(vnum3);
      ws.getRange(v+1, 5).setValue(vnum2);
    }
    break;
  case "Multiplication":
    ws.getRange(v+1, 2).setValue('x');
    ws.getRange(v+1, 4).setValue('x');
    ws.getRange(v, 3).setValue(vnum);
    ws.getRange(v+1, 3).setValue(vnum1);
    ws.getRange(v, 5).setValue(vnum2);
    ws.getRange(v+1, 5).setValue(vnum3);
    break;
  }
}
for ( var s = 8; s <= 26; s = s + 2){
  ks.getRange(s, 7).clearContent();
}
 for ( var s2 = 32; s2 <= 47; s2 = s2 + 3){
    ks.getRange(s2, 3).clearContent();
    ks.getRange(s2, 5).clearContent();
   }

}
function myKSG() {
 var ss = SpreadsheetApp.getActiveSpreadsheet();
 var ws = ss.getSheetByName("Worksheet");
 var ks = ss.getSheetByName("Key");

 for ( var s = 8; s <= 26; s = s + 2){
   var nm = ks.getRange(s, 3).getValue();
   var nm1 = ks.getRange(s, 5).getValue();

   switch(ws.getRange(s, 4).getValue()){
    case "+":
      ws.getRange(s, 4).copyFormatToRange(ks, 7, 7, s, s);
      ks.getRange(s, 7).setValue(nm + nm1);
      break;
    case "-":
      ws.getRange(s, 4).copyFormatToRange(ks, 7, 7, s, s);
      ks.getRange(s, 7).setValue(nm - nm1);
    break;
    case "x":
      ws.getRange(s, 4).copyFormatToRange(ks, 7, 7, s, s);
      ks.getRange(s, 7).setValue(nm * nm1);
    break;
   }
  }
  for ( var s2 = 32; s2 <= 47; s2 = s2 + 3){
    var vm = ks.getRange(s2 - 2, 3).getValue();
    var vm1 = ks.getRange(s2 - 1, 3).getValue();
    var vm2 = ks.getRange(s2 - 2, 5).getValue();
    var vm3 = ks.getRange(s2 - 1, 5).getValue();
    if( ks.getRange(s2-1, 2).getValue() == "+"){
      ks.getRange(s2, 3).setValue(vm + vm1);
   }
   else if(ks.getRange(s2-1, 2).getValue() == "-"){
      ks.getRange(s2, 3).setValue(vm - vm1);
    }
   else if(ks.getRange(s2-1, 2).getValue() == "x"){
     ks.getRange(s2, 3).setValue(vm * vm1);
   }
     if( ks.getRange(s2-1, 4).getValue() == "+"){
      ks.getRange(s2, 5).setValue(vm2 + vm3);
    }
    else if(ks.getRange(s2-1, 4).getValue() == "-"){
     ks.getRange(s2, 5).setValue(vm2 - vm3);
    }
     else if(ks.getRange(s2-1, 4).getValue() == "x"){
      ks.getRange(s2, 5).setValue(vm2 * vm3);
    }
   }
 }

The question deals with Maths worksheets, and specifically problems with solving equations for the addition of fractions.

This code is designed to update the results on the "Key" sheet for the fraction equations that appear on rows 8 to 26. Having established the logic and mechanism, the code can be adapted by the questioner to evaluate and update the formulae in rows 30 to 47.

The questioner should insert a new line 73 in their function "myWSG" to create the "addition sign" ensure addition applies for Fractions. I had a slight heart attack at one point when it appeared that the fractions were to be multiplied rather than added. No doubt, having established the mechanism for evaluating fractions, the questioner could adapt the code for subtraction, multiplication or division of fractions. But that is something best left for the Questioner to do at their leisure.

myWSG New line 73

ws.getRange(i, 4).setValue('+');

The evaluation of fractions required establishing a rubric to manage the various options and the appropriate treatment. I have added this as an addendum. This includes evaluating for zero value numerators (which the questioner may or may not have anticipated).

In cases where the each fraction has a different denominator, it's necessary to establish a "lowest common denominator" to make the fractions compatible. For this, I used the LCM (Least Common Multiple) function provided on the "Key" sheet. The only problem with this is that can result in a fraction that can be simplified. For example, if an answer is "1 26/40", then this can be simplified to "1 13/20". I shall leave the questioner to consider the pros and cons of this at their leisure.


function so_52469576() {

  // build solutions for fractions
  // Define the sdpreadsheet and sheets
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var ks = ss.getSheetByName("Key");

  // set/reset key variables
  var status = 0;
  var numtotal = 0;
  var answer = 0;
  var IntegerDenominator = 0;
  var IntegerNumerator = 0;
  var answercell = "";
  var Remainder = 0;
  var answerInteger = 0;
  var seqL = 0;
  var newnumL = 0;
  var seqR = 0;
  var newnumR = 0;
  var numL = 0; 
  var denL = 0; 
  var numR = 0; 
  var denR = 0; 
  var lcd = 0; 

  // start loop for equations in lows 8 to 26, every other row
  for (var i = 8; i <= 26; i = i + 2){

    //Logger.log("i="+i);//DEBUG

    // ensure some variables values don't carry over
    // might not be necessary
    status = 0;
    numtotal = 0;
    answer = 0;
    IntegerDenominator = 0;
    IntegerNumerator = 0;
    answercell = "";
    Remainder = 0;
    answerInteger = 0;
    seqL = 0;
    newnumL = 0;
    seqR = 0;
    newnumR = 0;
    numL = 0; 
    denL = 0; 
    numR = 0; 
    denR = 0; 
    lcd = 0; 

    // collect denominators and numerators
    numL = ks.getRange(i,16).getValue(); 
    denL = ks.getRange(i,17).getValue(); 
    numR = ks.getRange(i,19).getValue(); 
    denR = ks.getRange(i,20).getValue(); 
    lcd= ks.getRange(i,22).getValue(); 
    //Logger.log("i="+i+",numL="+numL+", denL="+denL+",numR="+numR+", denR="+denR+", lcd="+lcd); //DEBUG

    // commence evaluation
    // 1- test for an integer
    // Left side first
     if ((denL == "n/a") || (denL == 1)){
       // Left side is an integer
       status = 1;
       //Logger.log("denl is an integer"); //DEBUG
     }
     else{
       // Left side must be a Fraction
       status = 2;
       // Logger.log("denl is NOT an integer"); //DEBUG
     }

     // Right side
     if ((denR == "n/a") || (denR == 1)){
       // Left side is an integer
       status = status+1;
       // Logger.log("denR is an integer"); // DEBUG
     }
     else{
       // Left side must be a Fraction
       status = status+2;
       // Logger.log("denR is NOT an integer"); //DEBUG
     }

     // possible status values
     // 2 = Two Integers
     // 3 = One Integer and one Fraction
     // 4 = Two Fractions
     // There aretwo variations to Two Fractions: 1 - Same denominators; 2 - Different Denominators

     if (status == 2){

       //Logger.log("Status = 2 - Two Integers");
       // Two integers
       //get the numerator
       numtotal = numL + numR;
       answer = numtotal;
       //Logger.log("i="+i+",Result 2");//DEBUG
       answercell = ks.getRange(i, 7);
       answercell.setValue(answer);
       // end status 2 - Two Integers


     } else if (status == 3){ 

       //Logger.log("Status = 3 - One Integer and One Fraction");//DEBUG
       // One Integer and One Fraction
       // establish which side is the integer

       if (denL == "n/a" || denL == 1){
         // the integer is on the left
         IntegerDenominator = denR; //row, column Col L
         IntegerNumerator = numL * IntegerDenominator; 
         numtotal = IntegerNumerator + numR; 
         //Logger.log("i="+i+",Result 3-1-1");//DEBUG

       }else{
         // the integer is on the right
         IntegerDenominator = denL; //row, column Col L
         IntegerNumerator = numR * IntegerDenominator;
         numtotal = IntegerNumerator + numL;
         // Logger.log("i="+i+",Result 3-1-2");// DEBUG
       }


       // test for a numerator equal to zero
       // no intergers are = zero 
       // no denominators = zero

       if (numL==0 && numR==0){

         // doesn't apply for one integer and one fraction, 
         // but retain for consistency
         // answer must be zero

         answer = 0; 
         // Logger.log("i="+i+",Result 3-1");// DEBUG

       } else if  (numL == 0) {

       // if numL is zero, then the fraction must be on the left side
       // integer must be on the right
       // so answer is an integer

       answer = numR;
         //Logger.log("i="+i+",Result 3-2");//DEBUG

       } 
       else if (numR == 0) {

         // if numR is zero, then the fraction must be on the right side
         // so integer must be on the left  
         // so answer is an integer
         answer = numL;
         // Logger.log("i="+i+",Result 3-3");DEBUG

       } 
       else {

         // neither side = zero, so answer as normal
         answerInteger = parseInt(numtotal / IntegerDenominator);
         Remainder = numtotal-(answerInteger * IntegerDenominator);
         answer = " "+answerInteger+" "+Remainder+"/"+IntegerDenominator;
         // Logger.log("i="+i+",Result 3-4");// DEBUG
       }

       answercell = ks.getRange(i, 7);
       answercell.setValue(answer);
       // end status 3

     } else {

       //Logger.log("Status = 4 - Two Fractions");
       // Two Fractions

       // test for a numerator equal to zero
       // no intergers are = zero 
       // no denominators = zero

       if (numL==0 && numR==0){

         // doesn't apply for one integer and one fraction, 
         // but retain for consistency
         // answer must be zero

         answer = 0;
         // DEBUGLogger.log("i="+i+",Result 4-1: ");

       } else if  (numL == 0) {

         // if numL is zero, then fraction on the left must = zero
         // so only the fraction on the right applies
         // so answer is the righthand side
         answer = " "+numR+" "+"/"+denR;  
         //Logger.log("i="+i+",Result 4-2");//DEBUG

       } else if  (numR == 0) {

         // if numR is zero, then fraction on the right must = zero
         // so only the fraction on the left applies
         // so answer is the lefthand side
         answer = " "+numL+" "+"/"+denLR;  
         // Logger.log("i="+i+",Result 4-3");//DEBUG

       } else if (denL == denR && numL !=0 && numR!=0){

         // establish whehther same or different demoninators
         // same denominators
         numtotal = numL + numR;
         answerInteger = parseInt(numtotal / denL);
         Remainder = numtotal-(answerInteger * denL);
         answer = " "+answerInteger+" "+Remainder+"/"+denL;
         // Logger.log("i="+i+",Result 4-4");// DEBUG
         // end same denominators

       }
       else if (denL != denR && numL !=0 && numR!=0)
       {

         // Test for different denominators
         // Requires calculating the Lowest Common Denominator

         seqL = (lcd/denL);
         newnumL = seqL * numL;
         seqR = (lcd/denR);
         newnumR = seqR * numR;
         numtotal = newnumL+ newnumR;
         answerInteger = parseInt(numtotal/lcd);
         Remainder = numtotal-(answerInteger * lcd);
         answer = " "+answerInteger+" "+Remainder+"/"+lcd;  
         // Logger.log("i="+i+",Result4-5");// DEBUG
         // end different denominators

       }
         answercell = ks.getRange(i, 7);
         answercell.setValue(answer); 

     }// end status 4 - Two Fractions  
   }// end for  
}// end

Screenshot of solutions on "Key" sheet

在此处输入图片说明

Rubric - Calculation Logic

Need to establish the types of number in the equation so that we can apply the appropriate formula to solve. The goal is to distinguish between integers and fractions. And of the fractions, those with common denominator and those with different denominator. An overarching rule also applies, if either fraction has zero as the numerator, then its value is zero, and it can be ignored in the calculation.

  • Count the number of non-zero numerators (possibilities are one or two)
  • Count the number of non-zero denominators (possibilities are one or two)
  • Add the results (Possibilities are two, three or four)

POSSIBLE OUTCOMES
" Two integers " or " One integer" and one fraction " or " Two fractions "

TWO INTEGERS
Add the two numbers together and insert answer

ONE INTEGER AND ONE FRACTION

  • Convert the Integer to a fraction; get the denominator of the fraction and create a numerator of the same value

  • Add the two numerators

  • Divide the sum of the numerators by the denominator and express as an integer.

  • Calculate the remainder of the numerator (sum of the numerators less (integer result by the denominator))

  • Answer = Integer&space&remainder&/&denominator

TWO FRACTIONS There are two variations

  • Each fraction has the same denominator

  • Each fraction has a different denominator

Two Fractions - Same Denominator

  • Add the numerators

  • Divide the sum of the numerators by denominator and express the result as an integer

  • Calculate the remainder of the numerator (sum of the numerators less (integer result by the denominator))

  • Answer = Integer&space&remainder&/&denominator

Two Fractions - Different denominator

  • Find the lowest common denominator (LCM)

  • For each fraction, identify the respective sequence number that gives rise to LCM

  • For each fraction, multiply the numerator by the sequence number; this generates a "new" numerator for each fraction

  • Add the two "new" numerators

  • Divide the sum of the numerators by LCM and express as an integer.

  • Calculate the remainder of the numerator (sum of the "new" numerators less (integer result by the LCM))

  • Answer = Integer&space&remainder&/&LCM


IMPERFECTIONS: Lowest Common Denominator (LCD). The script relies on the LCM value on the "Key" sheet. This uses the Google function "LCM" to calculate the lowest common multiplier of the two denominators. LCM doesn't always generate true LCD because it it is solving the common multiplier, rather than the lowest common denominator. And this will never be the smaller of the two numbers.

For example

Assume the denominators are "6" and "2". The LCM value = 6, but the true Lowest common denominator is "2". 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM