剧情提要:
[机器小伟]在[工程师阿伟]的陪同下进入了[九转金丹]之第八转的修炼。设想一个场景:
如果允许你带一台不连网的计算机去参加高考,你会放弃选择一个手拿计算器和草稿本吗
?阿伟决定和小伟来尝试一下用计算机算高考题会是怎样的感觉。
正剧开始:
星历2016年05月24日 12:49:39, 银河系厄尔斯星球中华帝国江南行省。
[工程师阿伟]正在和[机器小伟]一起做着2010年的江苏省数学高考题]。
2010年江苏的这张高考试卷,是大家公认的一张难卷,难出了风格,
难出了特色,也难出了名。
想来世事也是如此无常,这一年的考生想必心里会想,这三届师兄们
做的题那就像玩一样,为啥轮到自己时会撞铁板呢。真是时也命也。好在
由于题量大,鸡蛋没放在一个篮子里,所以有切肤之痛的人应该不太多。
这一年的考卷,阿伟给评为6环,因为所有的题基本都是四、五环的难度,
然后题量还这么大。
<span style="font-size:18px;"> //题1 if (1) { var mathText = new MathText(); //希腊字母表(存此用于Ctrl C/V //ΑΒΓΔΕΖΗ ΘΙΚΛΜΝΞ ΟΠΡ ΣΤΥ ΦΧΨ Ω //αβγδεζη θικλμνξ οπρ στυ φχψ ω //希腊大小写字母 var Gc = 'ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ'; var Gs = 'αβγδεζηθικλμνξοπρστυφχψω'; var s = [ 'a + 2 = 3 => a = 1', 'a^[2] + 4 = 3 => a = NULL', '=> a = 1' ]; var x =40, y=40; var r1 = 40; var len = s.length; for (var i = 0; i < len; i++) { if (s[i] == '') { if (x < 100) { x += 300; y-=r1*3; } else { x = 20; y += r1; } } else { mathText.print(s[i], x, y, 'red', '|'); y+=r1; } } }</span>
<span style="font-size:18px;">#题2 def tmp2(): z = (6+4j)/(2-3j); print(abs(z)); >>> 2.0</span>
<span style="font-size:18px;">#题3 def tmp3(): P = 1-alg.combination(3, 2)/alg.combination(4, 2); print(P); >>> 0.5</span>
<span style="font-size:18px;">#题4 def tmp4(): p = [0.01, 0.01, 0.04,0.06, 0.05, 0.02, 0.01]; n = sum(p[:3])/sum(p)*100; print(n); >>> 30.0</span>
<span style="font-size:18px;"> //题5 if (1) { var mathText = new MathText(); //希腊字母表(存此用于Ctrl C/V //ΑΒΓΔΕΖΗ ΘΙΚΛΜΝΞ ΟΠΡ ΣΤΥ ΦΧΨ Ω //αβγδεζη θικλμνξ οπρ στυ φχψ ω //希腊大小写字母 var Gc = 'ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ'; var Gs = 'αβγδεζηθικλμνξοπρστυφχψω'; var s = [ 'f(1) = (e+ae^[-1])', 'f(-1) = -(e^[-1]+ae)', 'f(1) == f(-1) => a = -1' ]; var x =40, y=40; var r1 = 40; var len = s.length; for (var i = 0; i < len; i++) { if (s[i] == '') { if (x < 100) { x += 300; y-=r1*3; } else { x = 20; y += r1; } } else { mathText.print(s[i], x, y, 'red', '|'); y+=r1; } } }</span>
为了做这个题,阿伟也是拼了,不是说这个题多难,而是阿伟要借这个题来做一个大工具。
然后工具出炉了:
<span style="font-size:18px;">### # @usage 对于含有代数符号的等式及相关类型进行计算 # @author mw # @date 2016年05月24日 星期二 08:21:57 # @param # @return # ### #所有输入的字符串都是要符合(coef)*expr这种规范的 #相应转换可以调用alg.strmono处理单项式 #或调用alg.strformat来处理多项式 class StringAlgSolve(): #格式化输入的多项式阵列 def format(self, array): return alg.strformat(array); #把一个字符串阵列表示的多项式,转换成指定变量的系数多项式 #比如 ['(1/4)x^[2]', '-(1/12)y^[2]', '-1'], 以y作为参数 => ['(-(1/12))', 0, '(1/4)x^[2]+(-1)'] #传入的格式必须是已经格式化过的(coef)*x^[2]*y_[2]^[3]...这种类似形式 def coefTransfer(self, array, element): coefMap = []; len_ = len(array); len_2 = len(element); for i in range(len_): s = array[i]; len_3 = len(s); index = s.find(element); #参数的0次方 if (index == -1): coefMap.append([array[i], 0]); elif (index+len_2 < len_3 and s[index+len_2] != '^'): #参数的一次方 coefMap.append([s[:index-1]+s[index+len_2:], 1]); elif (index+len_2 >= len_3): #这里回退一个位置是因为根据格式参数之间有一个'*'号相连,要退掉 coefMap.append([s[:index-1], 1]); else: #左右中括号作为定界符,这就是为什么要求先格式化 LBracket = index+len_2+1; RBracket = s.find(']', LBracket); #幂的次数 exp_ = int(s[LBracket+1:RBracket]); coefMap.append([s[:index-1]+s[index+len_2:], exp_]); #对coefMap中的项按参数的次数进行合并 coefMap_2 = []; coefMap_2.append(coefMap[0]); for i in range(1, len(coefMap)): len_3 = len(coefMap_2); for j in range(len_3): if (coefMap_2[j][1] == coefMap[i][1]): coefMap_2[j][0] = coefMap_2[j][0]+ '+'+coefMap[i][0]; break; if (j >= len_3-1): coefMap_2.append(coefMap[i]); coefMap = coefMap_2; #把系数映射由高到低排列 coefMap = sorted(coefMap, key = lambda a : a[1], reverse = True); #返回的是参数的系数映射表[[coef, exp]...]对组 return coefMap; #返回参数的系数阵列 def coefArray(self, array, element): coefMap = self.coefTransfer(array, element); len_4 = len(coefMap); maxCoef, minCoef = coefMap[0][1], coefMap[len_4-1][1]; coefArray = ['0']*(maxCoef-minCoef+1); for i in range(len_4): coefArray[coefMap[i][1]] = coefMap[i][0]; coefArray.reverse(); return coefArray; #求解多项式的根(在参数情况下) def solvePoly(self, coefArray): len_ = len(coefArray); # #求解二次方程 if (len_ == 3): a, b, c = str(coefArray[0]), str(coefArray[1]), str(coefArray[2]); #注意,由于此处得出的系数阵列是这样的形式:['(-(1/12))', 0, '(1/4)x^[2]+(-1)'] #已经无法用alg中函数去做任何计算,只能纯粹进行字符串的叠加处理 delta = self.strAdd(self.strPow(b, '2'), self.strMul('-4', self.strMul(a, c))); #分子,分母 numerator = self.strAdd(self.strMinus('0', b), self.strPow(delta, '0.5')); numerator2 = self.strMinus(self.strMinus('0', b), self.strPow(delta, '0.5')); denomerator = self.strMul('2', a); return [self.strDiv(numerator, denomerator), self.strDiv(numerator2, denomerator)]; #求解一次方程 if (len_ == 2): a, b = str(coefArray[0]), str(coefArray[1]); return [self.strDiv(b, self.strMinus('0', a))]; return ''; #代数式里的两个代数式相乘,这里就是两个字符串相加的处理而已 def strMul(self, str1, str2): if (self.judgeZero(str1)): return ''; else: if (self.judgeZero(str2)): return ''; else: return '('+str1+')*('+str2+')'; #两个代数式相除 def strDiv(self, str1, str2): if (self.judgeZero(str1)): return ''; else: if (self.judgeZero(str2)): return '(inf)'; else: return '('+str1+')/('+str2+')'; #代数式相减 def strMinus(self, str1, str2): if (self.judgeZero(str1)): if (self.judgeZero(str2)): return ''; else: return '(-('+str2+'))'; else: if (self.judgeZero(str2)): return '('+str1+')'; else: return '('+str1+')-('+str2+')'; #代数式相加 def strAdd(self, str1, str2): if (self.judgeZero(str1)): if (self.judgeZero(str2)): return ''; else: return '('+str2+')'; else: if (self.judgeZero(str2)): return '('+str1+')'; else: return '('+str1+')+('+str2+')'; #代数式里的代数式乘方,这里就是字符串的处理而已 def strPow(self, str1, str2): if (self.judgeZero(str1)): return ''; else: if (self.judgeZero(str2)): return '('+str1+')'; else: return '('+str1+')^['+str2+']'; #判断字符串是否为0 def judgeZero(self, str1): for i in range(len(str1)): if (str1[i].isdigit() and str1[i] != '0'): #存在数字不为0, 所以这个代数式不为0 return False; #由于在规范化输出时已经保证了如果系数为0, 无论有多少参数都取0 #所以只要存在参数就说明代数式不为0 elif (str1[i].isalpha()): return False; return True; #给参数赋值,计算代数式的值 #比如输入 ('x^[2]+1', 'x', 3) => 10 #要确保给的条件足以让代数式计算出数值,否则肯定报错 def strEval(self, str1, element, elementValue): #代入数值,去指数 str1 = str1.replace(element, str(elementValue)); str1 = str1.replace('^[', '**'); str1 = str1.replace(']', ''); return eval(str1); </span>
这个工具能做的事很强大:
<span style="font-size:18px;">#题6 def tmp6(): # solve = StringAlgSolve(); f = ['(1/4)x^[2]', '-(1/12)y^[2]', '-1']; f = solve.format(f); print(f); #['(1/4)x^[2]', '(-(1/12))*y^[2]', '(-1)'] coef_y = solve.coefArray(f, 'y'); print(coef_y); ''' ['(((((-4)*(((-(1/12)))*((1/4)*x^[2]+(-1)))))^[0.5]))/((2)*((-(1/12))))', '((-((((-4)*(((-(1/12)))*((1/4)*x^[2]+(-1)))))^[0.5])))/((2)*((-(1/12))))'] ''' roots = solve.solvePoly(coef_y); print(roots); #双曲线右焦点 F = [4, 0]; for i in range(len(roots)): roots[i] = solve.strEval(roots[i], 'x', 3); distance = geo.distance2D([3, roots[i]], F); print(distance); print(roots); #[-3.872983346207417, 3.872983346207417] >>> ['(1/4)*x^[2]', '(-(1/12))*y^[2]', '(-1)'] ['(-(1/12))', '0', '(1/4)*x^[2]+(-1)'] ['(((((-4)*(((-(1/12)))*((1/4)*x^[2]+(-1)))))^[0.5]))/((2)*((-(1/12))))', '((-((((-4)*(((-(1/12)))*((1/4)*x^[2]+(-1)))))^[0.5])))/((2)*((-(1/12))))'] 4.0 4.0 [-3.872983346207417, 3.872983346207417]</span>
不得不说,这是[工程题阿伟]的一小步,却是[机器小伟]的一大步。
因为从此以后,[机器小伟]正式进入了可以解人族题的行列。
从很久以前阿伟一直在期待着Matlab或者python能放出一款能够这样解题
的程式,但人家却总是不出,没办法,自己动手吧。
现在既然阿伟有了,大家也就都有了。
<span style="font-size:18px;"> //题6 if (1) { var mathText = new MathText(); //希腊字母表(存此用于Ctrl C/V //ΑΒΓΔΕΖΗ ΘΙΚΛΜΝΞ ΟΠΡ ΣΤΥ ΦΧΨ Ω //αβγδεζη θικλμνξ οπρ στυ φχψ ω //希腊大小写字母 var Gc = 'ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ'; var Gs = 'αβγδεζηθικλμνξοπρστυφχψω'; var s = [ '(((((-4)*(((-(1/12)))*((1/4)*x^[2]+(-1)))))^[0.5]))', '/((2)*((-(1/12))))', '((-((((-4)*(((-(1/12)))*((1/4)*x^[2]+(-1)))))^[0.5])))', '/((2)*((-(1/12))))' ]; var x =40, y=40; var r1 = 40; var len = s.length; for (var i = 0; i < len; i++) { if (s[i] == '') { if (x < 100) { x += 300; y-=r1*3; } else { x = 20; y += r1; } } else { mathText.print(s[i], x, y, 'red', '|'); y+=r1; } } }</span>
<span style="font-size:18px;"> if (1) { var r = 20; config.setSector(1,1,1,1); config.graphPaper2D(0, 0, r); config.axis2D(0, 0,180); //坐标轴设定 var scaleX = 2*r, scaleY = 2*r; var spaceX = 2, spaceY = 2; var xS = -10, xE = 10; var yS = -10, yE = 10; config.axisSpacing(xS, xE, spaceX, scaleX, 'X'); config.axisSpacing(yS, yE, spaceY, scaleY, 'Y'); var transform = new Transform(); //存放函数图像上的点 var a = [], b = [], c = [], d = []; //需要显示的函数说明 //希腊字母表(存此用于Ctrl C/V //ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ //αβγδεζηθικλμνξοπρστυφχψω var f1 = 'x^[2]/4-y^[2]/16 = 1', f2 = '', f3 = '', f4 = ''; //函数描点 //参数方程 var x, y; var pointA = []; for (var thita = 0; thita < Math.PI*2; thita +=Math.PI/24) { a.push([2/Math.cos(thita), 2*1.732*Math.tan(thita)]); } //存放临时数组 var tmp = []; //显示变换 if (a.length > 0) { a = transform.scale(transform.translate(a, 0, 0), scaleX/spaceX, scaleY/spaceY); //函数1 tmp = [].concat(a); shape.pointDraw(tmp, 'red'); tmp = [].concat(a); shape.multiLineDraw(tmp, 'pink'); plot.setFillStyle('red'); plot.fillText(f1, 100, -180, 200); } } </span>
<span style="font-size:18px;">#题7 def tmp7(): S, n = 1, 1; while (S < 33): S = S + 2**n; if (S >= 33): break; n += 1; print(S);</span>
这个题就可以用上面那个工具来解,阿伟给大家展示下过程:
<span style="font-size:18px;">#题8 def tmp8(): solve = StringAlgSolve(); f = ['a_[k]^[2]', '-2a_[k]^[2]', '2a_[k]a_[k+1]']; f = solve.format(f); print('step 1: ', f); #['(1)*a_[k]^[2]', '(-2)*a_[k]^[2]', '(2)*a_[k]*a_[k+1]'] g = solve.coefTransfer(f, 'a_[k+1]'); print('step 2: ', g); #[['(2)*a_[k]', 1], ['(1)*a_[k]^[2]+(-2)*a_[k]^[2]', 0]] g = solve.coefArray(f, 'a_[k+1]'); print('step 3: ', g); #['(2)*a_[k]', '(1)*a_[k]^[2]+(-2)*a_[k]^[2]'] h = solve.solvePoly(g); print('step 4: ', h); a1 = 16; res = []; res.append(a1); for i in range(5): a_n = solve.strEval(h[0], 'a_[k]', res[-1]); res.append(a_n); print('step 5: ', res); #[16, 8.0, 4.0, 2.0, 1.0, 0.5] answer = res[0] + res[2] + res[4]; print('step 6: ', answer); >>> step 1: ['(1)*a_[k]^[2]', '(-2)*a_[k]^[2]', '(2)*a_[k]*a_[k+1]'] step 2: [['(2)*a_[k]', 1], ['(1)*a_[k]^[2]+(-2)*a_[k]^[2]', 0]] step 3: ['(2)*a_[k]', '(1)*a_[k]^[2]+(-2)*a_[k]^[2]'] step 4: ['((1)*a_[k]^[2]+(-2)*a_[k]^[2])/((-((2)*a_[k])))'] step 5: [16, 8.0, 4.0, 2.0, 1.0, 0.5] step 6: 21.0</span>
就是这么个过程,然后得到了正确的结果。
虽然工具草创,这条经脉还很弱,但毕竟是真正的打通了,以后添砖加瓦,
大有可为的。
倒数第二行是直接把生成的数据显示出来,这样,连打字都省了。
以后你会怎样做题? [机器小伟]已经可以为你代劳了。
<span style="font-size:18px;"> //题8 if (1) { var mathText = new MathText(); //希腊字母表(存此用于Ctrl C/V //ΑΒΓΔΕΖΗ ΘΙΚΛΜΝΞ ΟΠΡ ΣΤΥ ΦΧΨ Ω //αβγδεζη θικλμνξ οπρ στυ φχψ ω //希腊大小写字母 var Gc = 'ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ'; var Gs = 'αβγδεζηθικλμνξοπρστυφχψω'; var s = [ 'y = x^[2]', 'y\' = 2x', 'a_[k]^[2] = 2a_[k](a_[k]-a_[k+1])', 'a_[k+1] = ((1)*a_[k]^[2]+(-2)*a_[k]^[2])/((-((2)*a_[k])))', 'a_[1] = 16', ]; var x =40, y=40; var r1 = 40; var len = s.length; for (var i = 0; i < len; i++) { if (s[i] == '') { if (x < 100) { x += 300; y-=r1*3; } else { x = 20; y += r1; } } else { mathText.print(s[i], x, y, 'red', '|'); y+=r1; } } }</span>
时间不够了,下面阿伟就直接交白卷了。贴一下题。
这一年的附加题和上一年是两个极端,这一次非常的难。
本节到此结束,欲知后事如何,请看下回分解。