From d074410004bc2d0b618924f80aa07a6d3c0e592e Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Thu, 17 Jul 2025 23:37:06 +0800 Subject: [PATCH] feat: add modular inv --- .gitignore | 63 ++---------- build.gradle | 100 +++++++++++++++++++ build.json | 21 ++++ src/main/java/me/hatter/math/ModularInv.java | 63 ++++++++++++ 4 files changed, 194 insertions(+), 53 deletions(-) create mode 100644 build.gradle create mode 100644 build.json create mode 100644 src/main/java/me/hatter/math/ModularInv.java diff --git a/.gitignore b/.gitignore index 5760a7a..5def27e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,54 +1,11 @@ -# ---> Java -# Compiled class file -*.class - -# Log file -*.log - -# BlueJ files -*.ctxt - -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* -replay_pid* - -# ---> macOS -# General +out/ +build +classes .DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - +.gradle +.classpath +.project +.settings +*.iml +*.ipr +*.iws diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..41d4796 --- /dev/null +++ b/build.gradle @@ -0,0 +1,100 @@ +apply plugin: 'java' +apply plugin: 'eclipse' +apply plugin: 'idea' + +def JsonSlurper = Class.forName('groovy.json.JsonSlurper'); +def buildJSON = JsonSlurper.newInstance().parseText(new File("build.json").text) + +if (buildJSON.application) { apply plugin: 'application' } + +def baseProjectName = buildJSON?.project?.name ?: '__project_name__'; +def shellCommandName = baseProjectName +def eclipseProjectName = baseProjectName +def eclipseProjectComment = buildJSON?.project?.comment ?: '__project_name_comment__' +def jarManifestMainClass = buildJSON?.project?.main ?: 'SampleMain' + +if (buildJSON.application) { mainClassName = jarManifestMainClass } +archivesBaseName = buildJSON?.project?.archiveName ?: baseProjectName +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +def addRepo = new File(System.getProperty("user.home"), ".build_add.repo") + +repositories { + mavenLocal() + // mavenCentral() + maven() { url 'https://maven.aliyun.com/repository/central' } + if (addRepo.exists()) { maven() { url addRepo.text.trim() } } +} + +tasks.withType(JavaCompile) { + options.encoding = "UTF-8" +} + +// '-x test' skip unit test +defaultTasks 'packjar' + +task packjarsrc << { + ant.jar(destfile: "${baseProjectName}-sources.jar") { + fileset(dir: 'src/main/java', includes: '**/*.java') + } +} +packjarsrc.dependsOn build + +task packjar << { + def packtempclasses = "packtempclasses" + def libs = ant.path { + fileset(dir: 'build/libs', includes: '*.jar') + } + libs.list().each { + ant.unzip(dest: packtempclasses, src: it) + } + new File(packtempclasses + "/jar-version-build.txt").write(new Date().format("yyyyMMdd"), "UTF-8") + ant.jar(destfile: "${baseProjectName}.jar") { + fileset(dir: packtempclasses, includes: '**/*.*') + } + ant.delete(dir: packtempclasses) +} +packjar.dependsOn packjarsrc + +dependencies { + compile files(fileTree(dir: 'lib', includes: ['*.jar'], excludes: ['*-sources.jar', '*-javadoc.jar'])) + + if (buildJSON.repo != null && buildJSON.repo.dependencies != null) { + buildJSON.repo.dependencies.each { + compile("${it}") + } + } + if (buildJSON.repo != null && buildJSON.repo.testDependencies != null) { + buildJSON.repo.testDependencies.each { + testCompile("${it}") + } + } +} + +eclipse { + project { + name = eclipseProjectName + comment = eclipseProjectComment + } + classpath { + defaultOutputDir = file('classes') + downloadSources = true + file { + whenMerged { classpath -> + classpath.entries.findAll { it.kind=='lib' }.each { + if ((it.path != null) && (it.sourcePath == null) && file(it.path.replace(".jar", "-sources.jar")).exists()) { + it.sourcePath = getFileReferenceFactory().fromPath(it.path.replace(".jar", "-sources.jar")) + } + } + } + } + } +} + +eclipseJdt << { + File f = file('.settings/org.eclipse.core.resources.prefs') + f.write('eclipse.preferences.version=1\n') + f.append('encoding/=utf-8') +} + diff --git a/build.json b/build.json new file mode 100644 index 0000000..45f2251 --- /dev/null +++ b/build.json @@ -0,0 +1,21 @@ +{ + "project": { + "name": "math", + "main": "SampleMain", + "archiveName": "math" + }, + "application": false, + "java": "1.8", + "builder": { + "name": "gradle", + "version": "3.1" + }, + "repo": { + "dependencies": [ + "me.hatter:commons:3.0" + ], + "testDependencies": [ + "junit:junit:4.12" + ] + } +} diff --git a/src/main/java/me/hatter/math/ModularInv.java b/src/main/java/me/hatter/math/ModularInv.java new file mode 100644 index 0000000..bd7c7f2 --- /dev/null +++ b/src/main/java/me/hatter/math/ModularInv.java @@ -0,0 +1,63 @@ +package me.hatter.math; + +import java.math.BigInteger; +import java.util.Arrays; + +// https://zhuanlan.zhihu.com/p/426499159 +// def modular_inv(a, p): +// x, y, m = 1, 0, p +// while a > 1: +// q = a // m +// t = m +// +// m = np.mod(a, m) +// a = t +// t = y +// +// y, x = x - np.int64(q) * np.int64(y), t +// +// if x < 0: +// x = np.mod(x, p) +// return np.mod(x, p) +public class ModularInv { + + public static void main(String[] args) { + for (long i = 1; i < 10000; i++) { + for (long j = 1; j < 10000; j++) { + BigInteger a = BigInteger.valueOf(i); + BigInteger p = BigInteger.valueOf(j); + if (!a.gcd(p).equals(BigInteger.ONE)) { + continue; + } + BigInteger x = a.modInverse(p); + BigInteger y = modularInv(a, p); + System.out.println(Arrays.asList(a, p, a.modInverse(p), modularInv(a, p))); + if (!y.equals(x)) { + throw new RuntimeException(); + } + } + } + } + + public static BigInteger modularInv(BigInteger a, BigInteger p) { + BigInteger x = BigInteger.ONE; + BigInteger y = BigInteger.ZERO; + BigInteger m = p; + while (a.compareTo(BigInteger.ONE) > 0) { + BigInteger q = a.divide(m); + BigInteger t = m; + + m = a.mod(m); + a = t; + t = y; + + y = x.subtract(q.multiply(y)); + x = t; + + if (x.compareTo(BigInteger.ZERO) < 0) { + x = x.mod(p); + } + } + return x.mod(p); + } +}