diff --git a/cmd/crt.go b/cmd/crt.go new file mode 100644 index 0000000..707b60f --- /dev/null +++ b/cmd/crt.go @@ -0,0 +1,114 @@ +/* +Copyright © 2025 filifa + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +package cmd + +import ( + "fmt" + "log" + "math/big" + + "github.com/spf13/cobra" +) + +var remainders []string +var moduli []string + +func solveTwo(a1, n1, a2, n2 *big.Int) (*big.Int, *big.Int) { + m1 := new(big.Int) + m2 := new(big.Int) + tmp := new(big.Int) + tmp.GCD(m1, m2, n1, n2) + + x := new(big.Int).Set(a1) + x.Mul(x, m2) + x.Mul(x, n2) + + tmp.Set(a2) + tmp.Mul(tmp, m1) + tmp.Mul(tmp, n1) + + x.Add(x, tmp) + + N := new(big.Int).Set(n1) + N.Mul(N, n2) + + x.Mod(x, N) + + return x, N +} + +func crt(cmd *cobra.Command, args []string) { + if len(remainders) != len(moduli) { + log.Fatal("number of remainders and moduli do not match") + } + + // TODO: check for pairwise comprime + + n1 := new(big.Int) + a1 := new(big.Int) + for i := range remainders { + n2, ok := new(big.Int).SetString(moduli[i], 10) + if !ok { + log.Fatal("invalid input " + moduli[i]) + } + + a2, ok := new(big.Int).SetString(remainders[i], 10) + if !ok { + log.Fatal("invalid input " + remainders[i]) + } + + if i != 0 { + x, N := solveTwo(a1, n1, a2, n2) + n1.Set(N) + a1.Set(x) + } else { + a1.Set(a2) + n1.Set(n2) + } + } + + fmt.Println(a1) + fmt.Println(n1) +} + +// crtCmd represents the crt command +var crtCmd = &cobra.Command{ + Use: "crt -r R R [R ...] -m M M [M ...]", + Short: "Solve a system of linear congruences", + Long: `Solve a system of linear congruences.`, + Run: crt, +} + +func init() { + rootCmd.AddCommand(crtCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // crtCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // crtCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + + crtCmd.Flags().StringSliceVarP(&remainders, "remainders", "r", make([]string, 0), "remainders of congruences") + crtCmd.MarkFlagRequired("remainders") + + crtCmd.Flags().StringSliceVarP(&moduli, "moduli", "m", make([]string, 0), "moduli of congruences") + crtCmd.MarkFlagRequired("moduli") +}