[从头学数学] 第98节 负数

剧情提要:
[机器小伟]在[工程师阿伟]的陪同下进入练气期第十二层功法的修炼,
这次要修炼的目标是[负数]。

正剧开始:


星历2016年02月20日 09:49:52, 银河系厄尔斯星球中华帝国江南行省。
[工程师阿伟]正在和[机器小伟]一起研究起了负数。

09:47:48, 经过漫长辛苦的修炼,小伟终于达到了练气期十二层的水准。
09:48:43, 于是,小伟去向[人叫板老师]要来了第十二层功法。
09:49:16, 由于即将进入筑基期,所以这层功法的新内容就比较少了。


[人叫板老师]明确地在功法中指出,为了筑基成功,需要炼化这最后称作[整理和复习]的五枚筑基丹,小伟当即牢牢记下。


还是先来看看负数是什么吧。

[从头学数学] 第98节 负数_第1张图片

[人叫板老师]这次拿城市的气温来做引子。

说到了气温,小伟其实很怕热,一到夏天,什么CPU温度啊,显卡温度啊,很容易飘红啊。

但[工程师阿伟]却是很怕冷,冬天的那些满地白霜,枯黄的草总是会让阿伟心中很感寂寥。


[从头学数学] 第98节 负数_第2张图片

[从头学数学] 第98节 负数_第3张图片

虽然[人叫板老师]这次没有重点指明怎样读负数,但具有这个功能的工具小伟还是准备好了:

<span style="font-size:18px;">>>> 
负零点五五七 写作 -0.557
四千五百亿 写作 450000000000
负十四 写作 -14
九十九点七九 写作 99.79

###
# @usage   数字的中文写法 
# @author  mw
# @date    2016年01月08日  星期五  12:37:26 
# @param
# @return
#
###
def numberToChinese(num, s):
    if (num < 0):
        num = abs(num);
    chineseOfNumber=['零','一', '二', '三', '四', '五', '六',\
                     '七', '八', '九', '十','百','千','万','亿'];
    bit = 0;
    tmp = num;
    if (tmp == 0):
        s = chineseOfNumber[0];
    while (tmp > 0):
        tmp = tmp//10;
        bit+=1;
    tmp = num;
    while (tmp > 0):
        if (tmp < 10):
            s += chineseOfNumber[tmp];
            tmp -= 10;
        elif (tmp < 100):
            s += chineseOfNumber[tmp//10];
            s += '十';
            tmp = tmp%10; 
        elif (tmp < 1000):
            s += chineseOfNumber[tmp//100];
            s += '百';
            tmp = tmp%100;
            if tmp < 10 and tmp > 0:
                s += '零';
        elif (tmp < 10000):
            s += chineseOfNumber[tmp//1000];
            s += '千';
            tmp = tmp%1000;
            if tmp < 100 and tmp > 0:
                s += '零';
        elif (tmp < 100000000):
            s1 = '';
            s += numberToChinese(tmp//10000, s1);
            s += '万';
            tmp =tmp%10000;
            if tmp < 1000 and tmp > 0:
                s += '零';
        elif (tmp >= 100000000):
            s1 = '';
            s += numberToChinese(tmp//100000000, s1);
            s += '亿';
            tmp = tmp%100000000;
            if tmp < 10000000 and tmp > 0:
                s += '零';
        else:
            pass;
    return s;

###
# @usage   数字的中文写法转化为数字
# @author  mw
# @date    2016年01月08日  星期五  09:19:55 
# @param
# @return
#
###

def chineseToNumber(s):
    chineseOfNumber=['零','一', '二', '三', '四', '五', '六',\
                     '七', '八', '九', '十','百','千','万','亿'];
    result = 0;
    #每一组两个数,比如九百,一万,都是由一个值数和一个倍数组成。
    #不可能两个以上的值在一块,但可能两个以上的倍数在一块,比如九九不合法,但四百万合法。
    
    #合法表达为0,不合法为其它值
    illegal = 0;
    #两个长度
    lengthOfStr = len(s);
    lengthOfChs = len(chineseOfNumber);
    #合法性判断
    for i in range(lengthOfStr):
        if illegal == 1:
            break;

        for j in range(lengthOfChs):
            if s[i] == chineseOfNumber[j]:
                break;
            else:
                if j >= lengthOfChs-1:
                    print('含有非中文数字的字符,表达式不合法');
                    illegal = 1;

    for i in range(lengthOfStr-1):
        if illegal == 1:
            break;
        for j in range(10):
            if s[i] == chineseOfNumber[j]:
                if j>0:
                    for k in range(10):
                        if s[i+1] == chineseOfNumber[k]:
                            print('连续两个本数相连而没有倍数,表达式不合法。');
                            illegal = 1;
                            break;
                #当这个数是零时,它后面跟零或倍数都不合法
                else:
                    if s[i+1] == chineseOfNumber[0]:
                        print('连续两个零相连,表达式不合法。');
                        illegal = 1;
                        break;
                    
                    for k in range(10, lengthOfChs):
                        if s[i+1] == chineseOfNumber[k]:
                            print('零后面跟上倍数,表达式不合法。');
                            illegal = 1;
                            break;
                    
    
    for i in range(lengthOfStr-1):
        if illegal == 1:
            if (i > 0):
                print('表达式的倍数排序不符合规范,不合法。');
            break;                    
   
        if s[i] == '十':
            if s[i+1] == '十' or s[i+1] == '百' or s[i+1] == '千':
                illegal = 1;
        elif s[i] == '百':
            if s[i+1] == '十' or s[i+1] == '百' or s[i+1] == '千':
                illegal = 1;
        elif s[i] == '千':
            if s[i+1] == '十' or s[i+1] == '百' or s[i+1] == '千':
                illegal = 1;
        elif s[i] == '万':
            if s[i+1] == '十' or s[i+1] == '百' or s[i+1] == '千':
                illegal = 1;
        elif s[i] == '亿':
            if s[i+1] == '十' or s[i+1] == '百' or s[i+1] == '千' or s[i+1] == '万':
                illegal = 1;
        else:
            pass;

    #合法则计算      
    if illegal!=0:
        print('输入不合法。');
    else:
        value = 0;
        multiple = 1;
        result = 0;
        #超过亿的部分,单独分出来的原因是避免再和万的倍数相乘
        yiPart = 0;
        #超过万的部分
        wanPart = 0;
        for i in range(lengthOfStr):
            if s[i] == '亿':
                result += value+wanPart+yiPart;
                multiple = 100000000;
                value = result;
                result = value*multiple;
                if (i < lengthOfStr-1 and s[i+1] == '亿'):
                    value = 0;
                else:
                    yiPart = result;
                    result = 0;
                multiple = 1;
            elif s[i] == '万':
                result += value+wanPart;
                multiple = 10000;
                value = result;
                result = value*multiple;
                if (i < lengthOfStr-1 and (s[i+1] == '亿' or s[i+1] == '万')):
                    value = 0;
                else:
                    if (result > 100000000):
                        yiPart = result;
                    else:
                        wanPart = result;
                    result = 0;
                multiple = 1;
            elif s[i] == '千':
                multiple = 1000;
                result += value*multiple;
                value = 0;
                multiple = 1;
            elif s[i] == '百':
                multiple = 100;
                result += value*multiple;
                value = 0;
                multiple = 1;
            #十这个数字,即可以作为本数,也可以作为倍数
            elif s[i] == '十':
                if value == 0:
                    value = 10;
                    multiple = 1;
                    result += value*multiple;
                    value = 0;
                else:
                    multiple = 10;
                    result += value*multiple;
                    value = 0;
                    multiple = 1;
            else:
                for j in range(10):
                    if s[i] == chineseOfNumber[j]:
                        value = j;
                        multiple = 1;
                if i >= lengthOfStr-1:
                    result += value * multiple;

        result += wanPart + yiPart;
    #print('{0} {1}'.format(s, result));
    return result;

###
# @usage   小数的写法
# @author  mw
# @date    2016年02月02日  星期二  09:19:33 
# @param
# @return
#
###
def floatNumberWrite(s):
    #负号
    sign = 1;
    if s[0] == '负':
        sign = -1;
        s = s[1:];

    chineseOfNumber=['零','一', '二', '三', '四', '五', '六',\
                     '七', '八', '九'];
    result = 0;
    
    #小数点位置
    index = s.find('点');

    if (index != -1):
        #整数部分字符串
        sIntPart = s[:index];
        #小数部分字符串
        sFloatPart = s[index+1:];
        #小数精度位数
        accuracy = len(sFloatPart);
        #print(sIntPart);
        #print(sFloatPart);

        floatPart = 0;
        floatRate = 0.1;
        for i in range(accuracy):
            for j in range(10):
                if chineseOfNumber[j] == sFloatPart[i]:
                    floatPart += j * floatRate;
                    floatRate*=0.1;
                    break;

        intPart = chineseToNumber(sIntPart);
        result = sign*round(intPart + floatPart, accuracy);
    else:
        result = sign*chineseToNumber(s);
    return result;
    


###
# @usage   小数的读法
# @author  mw
# @date    2016年01月21日  星期四  09:53:40 
# @param
# @return
#
###
def floatNumberRead(num):
    #正负号
    if (num < 0):
        sign = '负';
    else:
        sign = '';

    #判断是否小数 
    sOfNum = str(num);
    index = sOfNum.find('.');
    if (index != -1):
        chineseOfNumber=['零','一', '二', '三', '四', '五', '六',\
                     '七', '八', '九'];
        sOfNum = sOfNum[index+1:];
        decimalPart = '点';
        for i in range(len(sOfNum)):
            decimalPart += chineseOfNumber[int(sOfNum[i])];
            
        import math;
        intPart = numberToChinese(math.floor(abs(num)), '');

        return sign+intPart+decimalPart;
    else:
        return sign+numberToChinese(num, '');           


def readNumber():
    a = [-29.5,0.84, 1.2, 1.8, 8844.43];
    for i in range(len(a)):
        print('{0} 读作 {1}'.format(a[i], floatNumberRead(a[i])));

def writeNumber():
    a = ['负零点五五七', '四千五百亿', '负十四', '九十九点七九'];
    for i in range(len(a)):
        print('{0} 写作 {1}'.format(a[i], floatNumberWrite(a[i])));
    

if __name__ == '__main__':
    #readNumber();
    writeNumber();
</span>

从此后,所有正数,负数,整数,小数都可以很轻松的读写了,当然,对于百分数,分数这些,还是做不到的,而且,如果数字太大,比如到了万亿这个级别,小伟似乎也会出错。但也不是绝对的:

<span style="font-size:18px;">>>> 
-291215454545455 读作 负二百九十一万二千一百五十四亿五千四百五十四万五千四百五十五
0.84 读作 零点八四
1.2 读作 一点二
1.8 读作 一点八
8844.43 读作 八千八百四十四点四三</span>

<span style="font-size:18px;">>>> 
负零点五五七 写作 -0.557
四千五百亿亿五百万 写作 45000000000005000000
负十四 写作 -14
九十九点七九 写作 99.79</span>





[从头学数学] 第98节 负数_第4张图片

[从头学数学] 第98节 负数_第5张图片

既然本次功法的内容很少,小伟就借着机会,来整理一下工具:

<span style="font-size:18px;">(130-100)÷100 = 0.3, 
(90-100)÷100 = -0.1, 
(95-100)÷100 = -0.05, 
(100-100)÷100 = 0, 

(130-100)/100 = 3/10, 
(90-100)/100 = -1/10, 
(95-100)/100 = -1/20, 
(100-100)/100 = 0, 

(130-100)/100 = 3/10 = 0.3 = 30%, 
(90-100)/100 = -1/10 = -0.1 = -10%, 
(95-100)/100 = -1/20 = -0.05 = -5%, 
(100-100)/100 = 0 = 0%, 

from fractions import *;
import traceback;
import math;

###
# @usage   混合运算
# @author  mw
# @date    2016年01月06日  星期三  09:33:22 
# @param
# @return
#
###
def calc():
    #import traceback;
    fin = open('input.txt');
    fout= open('output.txt', 'a');
    for line in fin.readlines():
        if line[-1] == '\n':
            line = line[:-1];     
            
        if line == '':
            continue;
        elif line.startswith('#'):
            print(line);
            fout.write(line+'\n');
        else:
            try:
                lines = line.split(sep=' ');
                for i in range(len(lines)):
                    if lines[i]=='':
                        continue;
                    try:
                        result = eval(lines[i]);
                        if (abs(result - int(result)) < 0.0001):
                            result = int(result);
                        else:
                            result = round(result, 3);
                        lines[i] = lines[i].replace('*','×');
                        lines[i] = lines[i].replace('//', '÷');
                        lines[i] = lines[i].replace('/', '÷');
                        s = '{0} = {1}'.format(lines[i], result);
                        print(s, end=', ');
                        fout.write(s + ', ');
                    except:
                        #traceback.print_exc();
                        ex = '{0} 表达式有误,无法进行计算。'.format(lines[i]);
                        print(ex);
                        fout.write(ex);
                print('\n');
                fout.write('\n');
            except:
                #traceback.print_exc();
                ex = '{0} 表达式有误,无法进行计算。'.format(lines[i]);
                print(ex);
                fout.write(ex);
            
    fout.write('\n');
    fout.close();
    fin.close();
    return;
###
# @usage   分数运算
# @author  mw
# @date    2016年01月15日  星期五  09:04:31 
# @param
# @return
#
###
def fractionCalc():
    
    # 可以将任意的四则运算表达式用分数进行计算,
    # 而不是将浮点结果简单转化成分数。
    fin = open('input.txt');
    fout= open('output.txt', 'a');
    
    for line in fin.readlines():
        if line[-1] == '\n':
            line = line[:-1];     
            
        if line == '':
            continue;
        elif line.startswith('#'):
            print(line);
            fout.write(line+'\n');
        else:
            try:
                lines = line.split(sep=' ');
                for i in range(len(lines)):
                    if lines[i]=='':
                        continue;
                    #消除空格
                    lines[i] = lines[i].replace(' ', '');
                    expCount = len(lines[i]);
                    expression = '';

                    #分割操作数
                    operands = [];
                    stmp = '';
                    indexBeg = 0;
                    indexEnd = 0;
                    for j in range(expCount):
                        if isOps(lines[i][j]):
                            if stmp != '':
                                operands.append(stmp);
                                stmp = '';
                        else:
                            stmp+=lines[i][j];
                    if stmp != '':
                        operands.append(stmp);
                    
                    print(operands);

                    #操作数修饰
                    operandCount = len(operands);
                    operandString = [];
                    #数字如1/7要转化成Fraction('1/7')这种样式才可以算出正确结果,引号不可以少掉。
                    for j in range(operandCount):
                        stmp = '';
                        stmp = 'Fraction(\''+operands[j]+'\')';
                        operandString.append(stmp);

                    #组装新表达式       
                    typechange = 1;
                    index = 0;
                    expression = '';
                    
                    for j in range(expCount):
                        #操作符直接添加
                        if  isOps(lines[i][j]):
                            expression+=lines[i][j];
                        else:
                            if j > 0 and typechange == 0 and isOps(lines[i][j-1]):
                                typechange = 1;
                            
                            #从操作数序列中选择对应操作数。
                            if typechange == 1:
                                if index > len(operandString):
                                    break;
                                expression += operandString[index];
                                index+=1;
                                typechange = 0;
                     
                    #表达式结果的运算打印
                    s = '{0} = {1}'.format(lines[i],eval(expression));
                    print(s, end=', ');
                    fout.write(s + ', ');
                print('\n');
                fout.write('\n');
            except:
                #traceback.print_exc();
                ex = '{0} 表达式有误,无法进行计算。'.format(lines[i]);
                print(ex);
                fout.write(ex);

    fout.write('\n');
    fout.close();
    fin.close();

def isOps(c):
    if c == '+' or c == '-' or c == '/' or c == '*' or c == '(' or c ==')':
        return 1;
    else:
        return 0;


###
# @usage   百分数,分数, 小数各结果的运算
# @author  mw
# @date    2016年02月19日  星期五  10:42:16 
# @param
# @return
#
###
def percentCalc():
    
    # 可以将任意的四则运算表达式用分数进行计算,
    # 而不是将浮点结果简单转化成分数。
    fin = open('input.txt');
    fout= open('output.txt', 'a');

    #结果为整数,此时小数表示和分数结果相同。
    resultIsInt = False;
    #结果绝对值大于10, 此时用百分数表示不合适。
    noPercentExpr = False;
    
    for line in fin.readlines():
        if line[-1] == '\n':
            line = line[:-1];     
            
        if line == '':
            continue;
        elif line.startswith('#'):
            print(line);
            fout.write(line+'\n');
        else:
            try:
                lines = line.split(sep=' ');
                for i in range(len(lines)):
                    if lines[i]=='':
                        continue;

                    #消除空格
                    lines[i] = lines[i].replace(' ', '');
                    expCount = len(lines[i]);
                    expression = '';
                    
                    resultIsInt = False;
                    noPercentExpr = False;
                    originExpr = lines[i];

                    #看表达式中是否有百分号
                    havePercentOp = False;
                    if lines[i].find('%') != -1:
                        havePercentOp = True;

                    OpsArray = [];
                    if havePercentOp == True:
                        for j in range(expCount):
                            #操作符直接添加
                            if  isOps(lines[i][j]):
                                OpsArray.append(lines[i][j]);
                            #处理百分号
                            if lines[i][j] == '%':
                                if len(OpsArray) > 0 and OpsArray[-1] == '/':
                                    expression+='*100';
                                else:
                                    expression+='/100';
                            else:
                                expression+=lines[i][j];

                        lines[i] = expression;
                        expCount = len(lines[i]);
                        expression = '';                   

                    #小数结果
                    floatResult = 0;
                    #百分数结果
                    percentResult = 0;
                    
                    result = eval(lines[i]);
                    if (abs(result)>10):
                        noPercentExpr = True;
                        
                    if (abs(result - int(result)) < 0.000001):
                        resultIsInt = True;
                        #小数结果
                        floatResult = int(result);
                        percentResult = int(result)*100;
                    else:
                        #小数结果
                        floatResult = round(result, 3);

                        result2 = result * 100;
                        if (abs(result2 - int(result2)) < 0.000001):
                            percentResult = int(result2);
                        else:
                            percentResult = round(result2, 3);                 

                    #分割操作数
                    operands = [];
                    stmp = '';
                    indexBeg = 0;
                    indexEnd = 0;
                    for j in range(expCount):
                        if isOps(lines[i][j]):
                            if stmp != '':
                                operands.append(stmp);
                                stmp = '';
                        else:
                            stmp+=lines[i][j];
                    if stmp != '':
                        operands.append(stmp);
                    
                    print(operands);

                    #操作数修饰
                    operandCount = len(operands);
                    operandString = [];
                    #数字如1/7要转化成Fraction('1/7')这种样式才可以算出正确结果,引号不可以少掉。
                    for j in range(operandCount):
                        stmp = '';
                        stmp = 'Fraction(\''+operands[j]+'\')';
                        operandString.append(stmp);

                    #组装新表达式       
                    typechange = 1;
                    index = 0;
                    expression = '';      
                    
                    
                    for j in range(expCount):
                        #操作符直接添加
                        if  isOps(lines[i][j]):
                            #记录操作符
                            OpsArray.append(lines[i][j]);
                            expression+=lines[i][j];
                        else:
                            if j > 0 and typechange == 0 and isOps(lines[i][j-1]):
                                typechange = 1;
                            
                            #从操作数序列中选择对应操作数。
                            if typechange == 1:
                                if index > len(operandString):
                                    break;
                                expression += operandString[index];
                                index+=1;
                                typechange = 0;                 


                    #设置打印格式
                    if noPercentExpr == True:
                        if resultIsInt == True:
                            s = '{0} = {1}'.format(originExpr,eval(expression));
                        else:
                            s = '{0} = {1} = {2}'.format(originExpr,eval(expression), floatResult);
                    else:
                        if resultIsInt == True:
                            s = '{0} = {1} = {2}%'.format(originExpr,eval(expression),percentResult);
                        else:
                            s = '{0} = {1} = {2} = {3}%'.format(originExpr,eval(expression), floatResult, percentResult);

                    print(s, end=', ');
                    fout.write(s + ', ');
                print('\n');
                fout.write('\n');
            except:
                #traceback.print_exc();
                ex = '{0} 表达式有误,无法进行计算。'.format(lines[i]);
                print(ex);
                fout.write(ex);

    fout.write('\n');
    fout.close();
    fin.close();

if __name__ == '__main__':
    print('>>>');
    calc();
    print('-----');
    fractionCalc();
    print('-----');
    percentCalc();
    print('<<<');
    print('');</span>

本节到此结束,欲知后事如何,请看下回分解。

你可能感兴趣的:([从头学数学] 第98节 负数)