From 6081757183d06ce433de08a5b6f9f082fc57f197 Mon Sep 17 00:00:00 2001 From: filifa Date: Fri, 5 Dec 2025 21:31:05 -0500 Subject: [PATCH] add quadratic residues sieve --- cmd/quadraticResidues.go | 72 ++++++++++++++++++++++++++++++++++ internal/lib/sieve/qresidue.go | 62 +++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 cmd/quadraticResidues.go create mode 100644 internal/lib/sieve/qresidue.go diff --git a/cmd/quadraticResidues.go b/cmd/quadraticResidues.go new file mode 100644 index 0000000..ad122e8 --- /dev/null +++ b/cmd/quadraticResidues.go @@ -0,0 +1,72 @@ +/* +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 ( + "bufio" + "fmt" + "os" + + "github.com/spf13/cobra" + "scm.dairydemon.net/filifa/mathtools/internal/lib/sieve" +) + +var quadraticResiduesN uint + +func quadraticResidues(cmd *cobra.Command, args []string) { + bufStdout := bufio.NewWriter(os.Stdout) + defer bufStdout.Flush() + + ch := sieve.QuadraticResidues(quadraticResiduesN, 1000) + for i := 0; ; i++ { + v, ok := <-ch + if !ok { + break + } + + if i == 0 { + continue + } + + fmt.Fprintln(bufStdout, v) + } +} + +// quadraticResiduesCmd represents the quadraticResidues command +var quadraticResiduesCmd = &cobra.Command{ + Use: "quadratic-residues", + Short: "Compute the number of quadratic residues for all moduli less than n", + Long: `Compute the number of quadratic residues for all moduli less than n.`, + Run: quadraticResidues, +} + +func init() { + sieveCmd.AddCommand(quadraticResiduesCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // quadraticResiduesCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // quadraticResiduesCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + + quadraticResiduesCmd.Flags().UintVarP(&quadraticResiduesN, "limit", "n", 0, "upper limit") + quadraticResiduesCmd.MarkFlagRequired("limit") +} diff --git a/internal/lib/sieve/qresidue.go b/internal/lib/sieve/qresidue.go new file mode 100644 index 0000000..a38b156 --- /dev/null +++ b/internal/lib/sieve/qresidue.go @@ -0,0 +1,62 @@ +/* +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 sieve + +func updatePowersOfTwo(sieve []uint, n uint) { + for q := uint(8); 2*q < n; q *= 2 { + sieve[2*q] = 2 * sieve[q] + } +} + +func updatePowersOfOddPrimes(sieve []uint, p uint, n uint) { + for q := p; p*q < n; q *= p { + sieve[p*q] = (p*q - q) / 2 + } +} + +/* +QuadraticResidues computes the number of quadratic residues modulo k for k=1 to n. +*/ +func QuadraticResidues(n uint, buflen uint) chan uint { + sieve := make([]uint, n) + for i := uint(0); i < n; i++ { + sieve[i] = 1 + } + + ch := make(chan uint, buflen) + go func() { + defer close(ch) + for i := uint(0); i < n; i++ { + if i == 0 || i == 1 || i == 4 || i == 6 || i == 8 || i == 12 || i == 24 || sieve[i] != 1 { + ch <- sieve[i] + continue + } + + if i == 2 { + updatePowersOfTwo(sieve, n) + } else { + sieve[i] = (i - 1) / 2 + updatePowersOfOddPrimes(sieve, i, n) + } + + updateMultiples(sieve, i, n, false) + ch <- sieve[i] + } + }() + + return ch +}