首页 > 解决方案 > 在谷歌脚本上用分数求解数学方程

问题描述

我正在制作一个 Google 表格程序来创建一个数学工作表,该工作表在某些参数内随机生成数字。

我在加法、减法、加法和减法的混合以及乘法方面取得了成功。我现在正在尝试将分数添加到组合中,但遇到了格式问题。虽然我已经能够生成随机分数并让它们正确显示,但问题在于尝试在密钥表上生成正确答案。

我试图找到一种方法将分数占用的单元格作为字符串读取并解析出单个数字,但这只会解决分子的问题,我仍然有分母的问题(找到共同的或至少有一个可以由学生或老师在解决后简化的答案)。

我在上面包含了一个链接,如果您有任何想法可以帮助解决此问题,请告诉我。

另外,由于我认为我没有在脚本中正确记录它,因此生成的整数的最大值位于“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);
    }
   }
 }

标签: javascriptmathgoogle-apps-scriptgoogle-sheets

解决方案


该问题涉及数学工作表,特别是解决分数加法方程的问题。

此代码旨在更新出现在第 8 到 26 行的分数方程的“关键”表上的结果。建立逻辑和机制后,提问者可以调整代码以评估和更新第 30 行中的公式到 47。

提问者应在其函数“myWSG”中插入新的第 73 行以创建“加法符号”以确保加法适用于分数。当分数似乎要相乘而不是相加时,我有一次轻微的心脏病发作。毫无疑问,在建立了评估分数的机制后,提问者可以调整代码进行分数的减法、乘法或除法。但这最好留给发问者在闲暇时做。

myWSG 新线 73

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

分数的评估需要建立一个标准来管理各种选项和适当的治疗。我已将此添加为附录。这包括评估零值分子(提问者可能预料到也可能没有预料到)。

在每个分数有不同分母的情况下,有必要建立一个“最小公分母”以使分数兼容。为此,我使用了“密钥”表上提供的 LCM(最小公倍数)函数。唯一的问题是这可能导致可以简化的分数。例如,如果答案是“1 26/40”,则可以简化为“1 13/20”。我会让提问者在闲暇时考虑这样做的利弊。


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

“Key”表上的解决方案截图

在此处输入图像描述

量规 - 计算逻辑

需要建立方程中数字的类型,以便我们可以应用适当的公式来求解。目标是区分整数和分数。而分数中,有共同分母的和不同分母的。一个总体规则也适用,如果任一分数的分子为零,则其值为零,在计算中可以忽略。

  • 计算非零分子的数量(可能是一两个)
  • 计算非零分母的数量(可能是一两个)
  • 添加结果(可能性为二、三或四)

可能的结果
两个整数”或“一个整数”和一个分数“或“两个分数

两个整数
将两个数字相加并插入答案

一个整数和一个分数

  • 将整数转换为分数;获取分数的分母并创建相同值的分子

  • 添加两个分子

  • 将分子之和除以分母并表示为整数。

  • 计算分子的余数(分子之和减去(分母的整数结果))

  • 答案 = 整数&空格&余数&/&分母

两个分数 有两种变化

  • 每个分数都有相同的分母

  • 每个分数都有不同的分母

两个分数 - 相同的分母

  • 添加分子

  • 将分子之和除以分母并将结果表示为整数

  • 计算分子的余数(分子之和减去(分母的整数结果))

  • 答案 = 整数&空格&余数&/&分母

两个分数 - 不同的分母

  • 找到最小公分母 (LCM)

  • 对于每个部分,确定产生 LCM 的相应序列号

  • 对于每个分数,将分子乘以序号;这会为每个分数生成一个“新”分子

  • 添加两个“新”分子

  • 将分子之和除以 LCM 并表示为整数。

  • 计算分子的余数(减去“新”分子的总和(LCM 的整数结果))

  • 答案 = 整数&空格&余数&/&LCM


缺陷:最小公分母 (LCD)。 该脚本依赖于“Key”表上的 LCM 值。这使用谷歌函数“LCM”来计算两个分母的最小公倍数。LCM 并不总是生成真正的 LCD,因为它解决的是公共乘数,而不是最低公分母。这永远不会是两个数字中较小的一个。

例如

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


推荐阅读