Code Monkey home page Code Monkey logo

digital's Introduction

digital

digital

Utilities for handling math and showing numbers in Java.

What is it?

There are only a few classes here, and any given application only is likely to use even fewer of them. Still, they're useful as a package, since they often depend on each other.

BitConversion allows converting float and double values to int and long versions of their underlying bits (and it does this in a way that works on GWT efficiently). While code that does this is available in the regular JDK in Float and Double, the implementations for those provided by GWT are extremely slow. BitConversion was initially meant just to provide a faster route for those conversions on GWT, but it also has some methods that convert float-int and double-long with reversed byte order (using a fast intrinsic on desktop JDKs and a special trick on GWT), and others that get only the low or high half of a double's bits as an int. It is modeled after the NumberUtils class from libGDX, but offers extra methods. It also has, purely for GWT purposes, an imul() method that acts just like integer multiplication on most platforms, but compiles down to a call to the JavaScript Math.imul() function on GWT, which automatically handles overflow in the same way a desktop JVM would. Similarly, countLeadingZeros() compiles to the JavaScript Math.clz32() function on GWT (or for long arguments, some small code that calls that), while using Integer.numberOfLeadingZeros() (or its Long counterpart) on non-GWT platforms. Counting leading zeros is an operation that shows up in a surprising assortment of places and is supposed to be fast, so having an alternative to this monstrosity is more than welcome. There's also countTrailingZeros() for int and long arguments, which compiles into a single call to Integer.numberOfTrailingZeros() (or using Long) on most platforms, or a JS two-liner on GWT that uses Math.clz32().

Base is much larger, and allows converting any Java primitive number type to a specific base/radix/number-system. Here, Bases are flexible enough to be able to be generated randomly for obfuscation purposes (such as to mangle a high score in a save file). There are several Base constants already defined. Each one can write numbers as signed (variable-length) or unsigned (fixed-length), as well as read back either type from one method. Parsing is significantly more relaxed than in the JDK, and invalid numbers tend to be returned as 0 rather than requiring an Exception to be caught. Base has some options when writing (or reading) a float or double. Like other numeric types, you can use signed() or unsigned() to write using the digits the Base usually uses, though here it writes the bits that compose the float or double for higher accuracy. Unlike other numeric types, there are base-10 decimal(), scientific(), general(), and friendly() methods to write floats/doubles with different rules for when to switch to scientific notation, if at all. These can be read back with readFloat() and readDouble(), while the signed/unsigned output needs readFloatExact() or readDoubleExact(). If you use a scrambled base (a random one, as mentioned before), then you need to use signed()/unsigned()/readFloatExact()/ readDoubleExact() to use the right scrambled digits. decimal() can take an exact length to limit large output to, or zero-pad small output to. Base can also combine the String representations of an array of primitives (or part of such an array, since 0.3.1) using join() or appendJoined(), and split apart Strings into arrays of primitives with methods like longSplit(), intSplit(), and floatSplit(). There are also now static methods with readable in their names; these output text that can be used in Java source code as numeric or character literals, for code generation. The Base.BASE10.readLong() method can read a long produced by Base.readable(long) just fine, because readLong() ignores invalid characters after the number (such as L in longs). Reading in the char literals this can produce requires using Base.readCharReadable().

TrigTools tries to be as complete as possible at covering trigonometric functions, offering sin, cos, tan, asin, acos, atan, and atan2 in radians, degrees, and turns. It also allows access to the lookup table used by sin and cos. Much of TrigTools can be seen as similar to what libGDX's MathUtils class offers, but allowing access to the lookup tables permits a few novel features (see its docs). It supports float and double arguments/returns for all functions. It also provides "smooth" sin and cos approximations that aren't table-based, and "smoother" sin/cos/tan versions that interpolate between entries in the lookup table for very high precision.

MathTools offers a wild grab bag of math functions and constants, from simple lerp, floor, ceil, and clamp methods to an optimized cube root function and parameterized splines. It is also based on MathUtils from libGDX. It supports float and double arguments/returns for most functions; some make sense for float only, like the optimized cube root. There's also a lot of commonly-defined constants, such as the square root of 2 and the golden ratio, as floats and doubles. Some methods here are useful in other mathematical code, like gamma and greatestCommonDivisor; others are more esoteric, like modularMultiplicativeInverse. There are some of the standard signal processing functions, such as triangle waves, square waves, and sawtooth waves. There are also a few functions here, "sway" and relatives, that look like sine waves when graphed, but are simpler to calculate internally. You can do some bitwise operations with MathTools, such as interleaving the bits of two numbers (also called a Morton code, or a position on the Z-Order Curve). There are ways to bring a float or double closer to 0.0 by the smallest possible amount. There's the fract() methods, familiar to shader programmers, that get the fractional part of a float or double. In general, if you need a math function that isn't trigonometry-related and doesn't do something with text, you may want to look here first.

ArrayTools provides common code for dealing with 2D arrays, and also sometimes 1D or 3D arrays. It allows copying, inserting, and filling 2D arrays, and creating ranges of 1D arrays. It also has a lot of methods for shuffling 1D arrays, 2D arrays, and sections of 1D arrays, for all primitive types and for objects. There are also some "filler supplies" in ArrayTools -- methods for filling up char, int, or String arrays with contents that are guaranteed to be distinct up to a certain limit. The same data that can be used to fill up arrays with ArrayTools also gets used by Hasher for seeding its predefined instances.

Hasher is... large. It provides fast, high-quality hashing functions for primitive arrays (and arrays of objects, if they implement hashCode()), and has 64-bit and 32-bit variants. The specific hashing algorithm it uses is a somewhat-hardened version of wyhash that doesn't use 128-bit math.

While Hasher can hash all types of 1D primitive array and most types of 2D primitive array, it can't do much with 3D or higher sizes at the moment. However, the only change that would be needed to add a hash() method for, say, a float[][][] is to copy the hash(float[][], int, int) method and change the first parameter to be a float[][][], so if you have the source, you can add this yourself with a quick copy and paste. Hasher allows you to specify the seed when you call hash() or hash64() (as static methods), but it also has a fairly-large array of predefined hash functions with instance methods for hash() and hash64(). Starting in 0.3.0, Hasher can either process a whole input array or part of one, specified by a start index and a length.

Hasher also has a few unary hashes that can be used as quick and dirty random number generators when applied to numbers in a sequence. The unary hashes can output longs, bounded ints, floats, and doubles, so they may be useful in a lot of cases. They are named like randomize1(), randomize2(), randomize3(), and so on, with higher numbers being typically slightly slower but also higher-quality (and more permissive of sets of inputs with atypical patterns). Most usage is probably served best by randomize3() and its bounded int, float, and double variants, since it uses a proven algorithm (MX3) and isn't much different on runtime performance.

While Hasher should usually change only very rarely, if at all, I was concerned about a few properties of the hashing code that might have meant some values would be returned less frequently, though this wasn't detectable to the SMHasher test suite. In version 0.4.0, Hasher's output for any given seed will be different from the same seed in previous versions. You can get the older Hasher instances either from Git history or the test folder's OldHasher v020 or OldHasher v037 files, if you need to reproduce the results of older seeds.

AlternateRandom is a quick micro-port of a random number generator from the closely-related juniper library. It is used only in ArrayTools here, as the default when no Random object is specified. The alternative would be to use a java.util.Random object, but that can't produce as many possible shuffles of mid-size arrays, and is slower, both of which AlternateRandom solves to some extent. If you don't use juniper, then AlternateRandom is a pretty good replacement for Random; if you do use juniper, then its WhiskerRandom or PasarRandom generators are similar to or the same as AlternateRandom's algorithm, and offer many more features.

ShapeTools provides some predefined mathematical constants for the vertices and faces of 3D polyhedra (currently, just the 5 Platonic solids). It could be useful for code that needs 3D shapes in code for something like continuous noise, but doesn't have access to 3D models.

TextTools provides some features that are similar to ones in Base, but different enough to belong in their own class. It operates on CharSequences usually, but sometimes needs Strings, so I'll just call this vague type "text." This class includes many different ways to search text for something, code to count the occurrences of text in a larger piece of text, code to join/split arrays of text and larger texts (this also works for boolean arrays), code for padding text, and code for replacing text with literals. This class mostly exists to avoid duplicating similar code that occurs often throughout my projects, and is related to code here.

Interpolations, along with its nested classes InterpolationFunction and Interpolator, provide a way to store and look up functions to smoothly interpolate between floats. This code is very similar to the Interpolation class in libGDX, and all the instances in Interpolation have a counterpart in Interpolations (there are some more here, as well). Creating an Interpolator registers its name in Interpolations' registry, where it can be looked up on its own with get(String) or as a group with getInterpolatorArray(). There are also ways to create one of the building blocks of an Interpolator, an InterpolationFunction, with methods in Interpolations. This makes creating new Interpolators with different parameters as easy as assigning a name to the generated function. Here's a sample page that shows how each Interpolator looks graphed.

How do I get it?

This library needs Java language level 8, but does not rely on any APIs introduced in Java 8. Targeting level 8 means this will work even if your project uses the newest Java versions (20 and later do not support targeting Java 7). Android projects should be able to use digital even without needing core library desugaring, as long as they target release 8 or higher. GWT can use digital without issue from GWT 2.8.0 up; GWT compatibility is a major focus of this library. RoboVM, for iOS, can use digital because no APIs are used from Java 8.

In a libGDX project, you must make sure the sourceCompatibility is 8 or higher in your core module and any other modules that use digital. This is currently not the default for gdx-setup projects, but is the default for gdx-liftoff projects. Liftoff also lets you just check a box to depend on digital.

To depend on digital with Gradle, add this to your dependencies (in your core module's build.gradle, for libGDX projects):

api "com.github.tommyettinger:digital:0.4.7"

If you target GWT using libGDX, you will also need this in your html module's build.gradle:

api "com.github.tommyettinger:digital:0.4.7:sources"

GWT needs to be told about these changes in your GdxDefinition.gwt.xml file. For digital 0.1.7 and later, use:

<inherits name="com.github.tommyettinger.digital" />

If you are using 0.1.6 or older, there are probably some GWT compatibility issues, but you can try using this, or preferably updating to 0.1.7 or later:

<inherits name="digital" />

You can also use JitPack to get a recent commit; in that case, follow its instructions here. This also has instructions for Maven and other build tools.

License

Apache 2.0. This includes some modified code from libGDX, SquidLib, SquidSquad, Uncommon Maths, wyhash, Apache Commons Lang, and Ryu. More code is not from a particular repository (for example, some is from Wikipedia); see each file for specific author credits. The Ryu code is more substantial than the other projects, and even though its license is also Apache 2.0, I included its license here as LICENSE-RYU.txt. The Ryu code that is relevant to what we use here is also replicated with only minor compatibility changes in the src/test folder. There's some cases where an individual method was ported from another permissively-licensed repo, such as a_cbrt from Stand-alone-junk (Marc B. Reynolds' in-progress code), or probit from P.J. Acklam's site (archived), and for most of these I have tried to provide credit and a link to the source in the documentation for that method.

digital's People

Contributors

jmcwilliams403 avatar tommyettinger avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

jmcwilliams403

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.