代码之家  ›  专栏  ›  技术社区  ›  despinxz

MIPS:如何在使用双打时保持精度或将其四舍五入到特定的小数位数?

  •  0
  • despinxz  · 技术社区  · 1 年前

    我正在MIPS汇编(使用MARS)中编写一个程序,该程序从.txt文件中读取数字并将其加载到向量中。其中一些数字是双倍的。该程序及其逻辑通常可以工作,但我对一些计算不正确的数字有问题。例如,.txt文件中为0.672的数字存储为0.6719999999999999。故障偶尔会在添加中发生。有什么方法可以解决这个问题?

    如果你好奇,这里是我的代码(评论是葡萄牙语):

    .data
    
    fim: .double -1.0
    zero: .double 0.0
    dez: .double 10.0
    
    filename: .asciiz "xtrain.txt"
    quebra_linha: .asciiz "\n"
    espaco: .asciiz " "
    
    buffer: .space 17408
    
    .align 3
    vetor: .space 4000
    
    .text
    ler_arq:    # lê o arquivo
        la $a0, filename
        li $a1, 0
        li $a2, 0
        
        li $v0, 13
        syscall
    
    load:       # carrega arquivo no buffer
        move $a0, $v0
        la $a1, buffer
        li $a2, 17408
        
        li $v0, 14
        syscall
    
    ler_nums:   # lê byte por byte do arquivo
        la $s0, vetor
        move $s1, $s0
        la $t0, buffer
        l.d $f10, dez
        
        copy_num:
            lb $t1, 0($t0)      # carrega caracter atual em t1
            
            bne $t1, '.', cont  # se o caracter não for um ponto, pula as próximas linhas
            li $t3, 1       # se for um ponto, t3 é setado para 1 (como se fosse True)
            addiu $t0, $t0, 1
            lb $t1, 0($t0)      # avança para o próximo byte
            
            cont:
            beq $t1, ',', num_end
            beq $t1, '\r', num_end
            beq $t1, '\n', fim_copia    # se o caracter for uma vírgula ou quebra de linha, termina de copiar o número atual
            beq $t1, 0, end         # se o arquivo terminar, vai para o fim do código
            
            subu $t1, $t1, 48       # transforma ascii em int
            
            beq $t3, 1, le_double       # se t3 for True, pula para le_double
            
            le_int:
                mul $t2, $t2, 10    # multiplica o int armazenado anteriormente por 10
                add $t2, $t2, $t1   # adiciona o caracter atual
                j fim_copia     
            
            le_double:
                mtc1 $t1, $f0
                cvt.d.w $f0, $f0    # converte para double
                
                addiu $t4, $t4, 1   # contador de 10
                
                # loop para dividir o número por 10^t4
                loop_double:
                    div.d $f0, $f0, $f10
                    addiu $t5, $t5, 1
                    blt $t5, $t4, loop_double
                
                add.d $f2, $f2, $f0
                li $t5, 0
                
                j fim_copia
            
            num_end:
                mtc1 $t2, $f4
                cvt.d.w $f4, $f4    # converte para double
                
                add.d $f4, $f4, $f2
                
                s.d $f4, 0($s1)
                
                li $t2, 0       # reinicia acumulador inteiro
                li $t3, 0       # seta t3 pra False
                li $t4, 0       # reinicia contador 10
                
                l.d, $f0, zero      # reinicia f0
                l.d, $f2, zero
                
                addiu $s1, $s1, 8   # avança posição no vetor
                
                j fim_copia
            
            fim_copia:
                addiu $t0, $t0, 1
                j copy_num
    
    end:
        mtc1 $t2, $f0
        cvt.d.w $f0, $f0
        s.d $f0, 0($s1)     # carrega o último número no vetor
        addiu $s1, $s1, 8
        l.d $f0, fim        # carrega -1.0 no fim do vetor
        s.d $f0, 0($s1)
        l.d $f12, 0($s0)    # passa o início do vetor para f12 como parâmetro
        
        # loop para printar cada linha e número do programa
        loop:
            addiu $t9, $t9, 1
            
            li $v0, 3
            syscall
            
            la $a0, espaco
            li $v0, 4
            syscall
            
            addi $s0, $s0, 8
            l.d $f12, 0($s0)
            
            bne $t9, 8, cont_fq
            
            la $a0, quebra_linha
            li $v0, 4
            syscall
            
            li $t9, 0
            
            cont_fq:
            c.eq.d $f12, $f0
            bc1f loop
                
     
    
    

    我试过从双精度变为单精度,老实说,我不确定还能尝试什么。

    0 回复  |  直到 1 年前