Task: P-Adic numbers, basic




Go: package main

import "fmt"


const EMX = 64      
const DMX = 100000  
const AMX = 1048576 
const PMAX = 32749  


var p1 = 0
var p = 7  
var k = 11 

func abs(a int) int {
    if a >= 0 {
        return a
    }
    return -a
}

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}

type Ratio struct {
    a, b int
}

type Padic struct {
    v int
    d [2 * EMX]int 
}


func (pa *Padic) r2pa(q Ratio, sw int) int {
    a := q.a
    b := q.b
    if b == 0 {
        return 1
    }
    if b < 0 {
        b = -b
        a = -a
    }
    if abs(a) > AMX || b > AMX {
        return -1
    }
    if p < 2 || k < 1 {
        return 1
    }
    p = min(p, PMAX)  
    k = min(k, EMX-1) 
    if sw != 0 {
        fmt.Printf("%d/%d + ", a, b)   
        fmt.Printf("0(%d^%d)\n", p, k) 
    }

    
    pa.v = 0
    p1 = p - 1
    pa.d = [2 * EMX]int{}
    if a == 0 {
        return 0
    }
    i := 0

    
    for b%p == 0 {
        b = b / p
        i--
    }
    s := 0
    r := b % p

    
    b1 := 1
    for b1 <= p1 {
        s += r
        if s > p1 {
            s -= p
        }
        if s == 1 {
            break
        }
        b1++
    }
    if b1 == p {
        fmt.Println("r2pa: impossible inverse mod")
        return -1
    }
    pa.v = EMX
    for {
        
        for a%p == 0 {
            a = a / p
            i++
        }

        
        if pa.v == EMX {
            pa.v = i
        }

        
        if i >= EMX {
            break
        }

        
        if (i - pa.v) > k {
            break
        }

        
        pa.d[i+EMX] = a * b1 % p
        if pa.d[i+EMX] < 0 {
            pa.d[i+EMX] += p
        }

        
        a -= pa.d[i+EMX] * b
        if a == 0 {
            break
        }
    }
    return 0
}


func (pa *Padic) dsum() int {
    t := min(pa.v, 0)
    s := 0
    for i := k - 1 + t; i >= t; i-- {
        r := s
        s *= p
        if r != 0 && (s/r-p != 0) {
            
            s = -1
            break
        }
        s += pa.d[i+EMX]
    }
    return s
}


func (pa *Padic) add(b Padic) *Padic {
    c := 0
    r := Padic{}
    r.v = min(pa.v, b.v)
    for i := r.v; i <= k+r.v; i++ {
        c += pa.d[i+EMX] + b.d[i+EMX]
        if c > p1 {
            r.d[i+EMX] = c - p
            c = 1
        } else {
            r.d[i+EMX] = c
            c = 0
        }
    }
    return &r
}


func (pa *Padic) cmpt() *Padic {
    c := 1
    r := Padic{}
    r.v = pa.v
    for i := pa.v; i <= k+pa.v; i++ {
        c += p1 - pa.d[i+EMX]
        if c > p1 {
            r.d[i+EMX] = c - p
            c = 1
        } else {
            r.d[i+EMX] = c
            c = 0
        }
    }
    return &r
}


func (pa *Padic) crat() {
    fl := false
    s := pa
    j := 0
    i := 1

    
    for i <= DMX {
        
        j = k - 1 + pa.v
        for j >= pa.v {
            if s.d[j+EMX] != 0 {
                break
            }
            j--
        }
        fl = ((j - pa.v) * 2) < k
        if fl {
            fl = false
            break
        }

        
        j = k - 1 + pa.v
        for j >= pa.v {
            if p1-s.d[j+EMX] != 0 {
                break
            }
            j--
        }
        fl = ((j - pa.v) * 2) < k
        if fl {
            break
        }

        
        s = s.add(*pa)
        i++
    }
    if fl {
        s = s.cmpt()
    }

    
    x := s.dsum()
    y := i
    if x < 0 || y > DMX {
        fmt.Println(x, y)
        fmt.Println("crat: fail")
    } else {
        
        i = pa.v
        for i <= -1 {
            y *= p
            i++
        }

        
        if fl {
            x = -x
        }
        fmt.Print(x)
        if y > 1 {
            fmt.Printf("/%d", y)
        }
        fmt.Println()
    }
}


func (pa *Padic) printf(sw int) {
    t := min(pa.v, 0)
    for i := k - 1 + t; i >= t; i-- {
        fmt.Print(pa.d[i+EMX])
        if i == 0 && pa.v < 0 {
            fmt.Print(".")
        }
        fmt.Print(" ")
    }
    fmt.Println()
    
    if sw != 0 {
        pa.crat()
    }
}

func main() {
    data := [][]int{
        
        {2, 1, 2, 4, 1, 1},
        {4, 1, 2, 4, 3, 1},
        {4, 1, 2, 5, 3, 1},
        {4, 9, 5, 4, 8, 9},
        {26, 25, 5, 4, -109, 125},
        {49, 2, 7, 6, -4851, 2},
        {-9, 5, 3, 8, 27, 7},
        {5, 19, 2, 12, -101, 384},
        
        {2, 7, 10, 7, -1, 7},
        {34, 21, 10, 9, -39034, 791},
        
        {11, 4, 2, 43, 679001, 207},
        {-8, 9, 23, 9, 302113, 92},
        {-22, 7, 3, 23, 46071, 379},
        {-22, 7, 32749, 3, 46071, 379},
        {35, 61, 5, 20, 9400, 109},
        {-101, 109, 61, 7, 583376, 6649},
        {-25, 26, 7, 13, 5571, 137},
        {1, 4, 7, 11, 9263, 2837},
        {122, 407, 7, 11, -517, 1477},
        
        {5, 8, 7, 11, 353, 30809},
    }

    sw := 0
    a := Padic{}
    b := Padic{}

    for _, d := range data {
        q := Ratio{d[0], d[1]}
        p = d[2]
        k = d[3]
        sw = a.r2pa(q, 1)
        if sw == 1 {
            break
        }
        a.printf(0)
        q.a = d[4]
        q.b = d[5]
        sw = sw | b.r2pa(q, 1)
        if sw == 1 {
            break
        }
        if sw == 0 {
            b.printf(0)
            c := a.add(b)
            fmt.Println("+ =")
            c.printf(1)
        }
        fmt.Println()
    }
}