num-traits: the numeric trait vocabulary generic Rust code depends on
Numeric traits for generic mathematics in Rust
At a glance
- What is it?
- num-traits is the crate that defines the numeric traits Rust generic code bounds against, with an optional std feature that can be turned off for no_std builds and a libm fallback that keeps Float and Real available without the standard library.
- Who is it for?
- Adopt num-traits when you write generic Rust over primitive numbers, since a shared trait vocabulary is what lets your crate interoperate with other crates instead of inventing a private bound, and because the same dependency works for standard library and no_std targets once you pick the right feature set. Do not adopt it when you only handle one concrete type, where the inherent methods on the primitive are enough and the dependency is dead weight.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 107 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A shared vocabulary so generic code can talk about numbers
Rust generics need a bound. When a function is generic over a number, the bound is what says which operations the body may call, and if every crate invented its own trait for that, nothing would interoperate. num-traits exists to be that shared vocabulary.
The crate description is Numeric traits for generic mathematics, and the keywords in the package metadata are mathematics and numerics, with categories covering algorithms, science and no-std. That is the whole scope. It is a trait library, not a numeric implementation: it does not ship a big number type, it does not do matrix work, it does not provide a complex number. It defines the interfaces, and the primitive types in the standard library implement them.
The audience is library authors, not application developers. An application that only ever multiplies two f64 values has no use for this crate. A library that wants to offer a generic numerical routine, and wants other people's libraries to be able to call it, wants exactly this.
One detail of the repository layout says a lot about the design. There is a build.rs, a single [build-dependencies] entry on autocfg, and a src/ directory. The crate is a set of trait definitions and impls, with a small amount of compile time machinery to detect which numeric features the target platform actually provides.
Float and Real vanish without std or libm
The feature model is the part of this crate that trips people up, and the README is unusually direct about it.
The default feature set is std. With it disabled the crate works in a no_std context, as the README states by saying the crate can be used without the standard library with #![no_std]. But then the cost appears: the Float and Real traits are only available when either std or libm is enabled.
That is the whole rule in two sentences. FloatCore is always available. MulAdd and MulAddAssign for f32 and f64 require std or libm, as do the implementations of signed and floating point exponents in Pow.
So a no_std crate that wants the full floating point trait set has to pull in libm, the pure Rust math library, as an optional dependency. In Cargo.toml the optional dependency is libm at version 0.2.0, and the feature that turns it on is libm = ["dep:libm"], with std = [] and default = ["std"]. The dependency name and the feature name are deliberately kept distinct, so enabling the feature is what pulls the crate in rather than the other way around.
The practical consequence for a downstream user is that a no_std consumer who forgot the libm feature does not get a compile error about a missing method, they get an error that the trait they are asking for does not exist at all.
Vestigial features and a build script that detects capabilities
Two entries in Cargo.toml describe the crate's history more than its current behaviour.
The first is the i128 feature, marked in the file as a vestigial feature that is now always in effect. It exists so that older manifests that enable it keep working, since a removed feature would break a build outright, whereas an ignored one does not. This is a common pattern in long lived Rust crates, and it is a reminder that the feature list is part of the public interface.
The second is build.rs together with autocfg. The crate compiles a small build script to detect properties of the target, which is how a library can decide whether to provide an impl for a type the platform does not actually have. For a trait crate this is close to the minimum machinery needed, and the presence of ci/ and tests/ directories alongside it suggests the detection is checked rather than assumed.
The package metadata also carries the docs.rs configuration, which sets features = ["std"] for the published documentation and passes --generate-link-to-definition as a rustdoc argument. That last setting is worth noting if you read the generated docs: trait methods link to their definitions rather than being inlined, which makes a long trait definition in the docs readable instead of repetitive.
Adding the dependency is the whole installation
There is nothing to build and nothing to configure. The README gives one instruction for usage, adding the crate to your Cargo.toml:
[dependencies]
num-traits = "0.2"For a no_std target, the README gives the longer form, with the std feature turned off and the libm line present but commented:
[dependencies.num-traits]
version = "0.2"
default-features = false
# features = ["libm"] # <--- Uncomment if you wish to use `Float` and `Real` without `std`The comment is the instruction. Uncommenting that one line is the difference between having Float and Real available in a no_std build and not having them.
The version you request is 0.2, and the version recorded in the package metadata is 0.2.19. The dependency declaration carries no version pin beyond that, so the resolution of a compatible 0.2.x release is left to your own workspace and lockfile.
What you write next is a bound. The traits the documentation names in this repository are Float, Real, FloatCore, MulAdd, MulAddAssign and Pow, and those names are what a generic signature in your own crate will refer to.
Using the standard library's inherent methods instead
There is a real alternative, and it is the one most Rust code uses. The primitive types carry their own inherent methods, so a function that takes an f64 and calls sqrt on it needs no trait at all. That approach has no dependency, no feature flags and no generic bounds, and it is the right choice the moment the type in your signature is fixed.
The difference appears the moment the type is not fixed. Inherent methods cannot be called through a generic parameter, because the compiler does not know which concrete type is behind it. A generic function that wants to call a mathematical operation has to name a trait, and if it names its own private trait, then a caller with a different generic bound cannot use it and your crate cannot compose with anyone else's numeric trait.
That is the specific problem num-traits solves. It is not about performance, and it is not about adding capabilities to the primitives. It is about having one set of names, so that a routine written against Float in your crate can be called with a type that implements Float in someone else's.
The other alternative is the libm path itself, which is not a competitor but a switch inside this crate: enabling std gives you the standard library implementations, enabling libm gives you the same traits backed by a pure Rust math library when the standard library is unavailable.
Dual licensing and how contributions are handled
num-traits is licensed under either of two licences, at your option: the Apache License, Version 2.0, or the MIT license. The package metadata records the same choice as MIT OR Apache-2.0, and both licence texts sit at the repository root as LICENSE-APACHE and LICENSE-MIT.
The dual licence matters more than it looks for a dependency this fundamental. A crate that is only usable under one licence can be excluded by a policy; a crate available under either of the two most permissive licences in common use is not. That choice is made by the upstream project, and it is one reason a trait crate with a low level of API surface can still sit comfortably in a large dependency tree.
The contribution terms are stated as well. The README says that unless a contributor explicitly states otherwise, a contribution intentionally submitted for inclusion, as defined in the Apache-2.0 licence, is dual licensed as above with no additional terms or conditions. In practice that means the relicensing election is made once, by the project, and contributors do not have to negotiate a licence for each pull request.
None of this is legal advice, and the practical point is narrower: check which of the two your organisation requires, because the choice is available to you and the files are in the repository.
Release notes live in the repository, not in GitHub releases
This repository publishes no GitHub releases. The versioning information you would normally look for on a releases page is instead in RELEASES.md in the repository root, which the README points to for release notes.
That arrangement suits a crate of this kind. The API surface is stable and the version number moves slowly, so a list of changes in a file in the tree is enough, and it avoids the noise of tagging a release for a patch that only adjusts trait bounds for a new compiler version.
The repository is not archived, and the last push was on 2026-07-07. The crate declares rust-version = "1.60" and the README states that it is tested for rustc 1.60 and greater, with a minimum rustc 1.60 badge, and the edition is 2021. That combination sets the floor for every downstream project: a workspace that still has to build on an older compiler can keep this dependency, and a project on a modern toolchain gains nothing special from a newer minimum.
One last packaging note. The package metadata excludes /ci/* and /.github/* from the published package, so the published crate carries the library and its tests, not the repository's own continuous integration configuration. That keeps the artefact small, and it is a reminder that the CI setup you see in the repository is not something you inherit by depending on the crate.
Editorial conclusion
Adopt num-traits when you write generic Rust over primitive numbers, since a shared trait vocabulary is what lets your crate interoperate with other crates instead of inventing a private bound, and because the same dependency works for standard library and no_std targets once you pick the right feature set. Do not adopt it when you only handle one concrete type, where the inherent methods on the primitive are enough and the dependency is dead weight. Before you commit, verify two things in your own build: that the traits you bound on are the ones you think, since Float and Real disappear entirely when neither std nor libm is enabled and FloatCore is the only one always present, and that the rust-version of 1.60 recorded in Cargo.toml is acceptable to your toolchain policy, since the crate is tested for rustc 1.60 and greater.
Frequently asked questions
What Rust version does num-traits support?
Cargo.toml records rust-version = "1.60" and edition 2021, and the README states that the crate is tested for rustc 1.60 and greater.
How do I use num-traits in a no_std crate?
Disable the default std feature and, if you need Float or Real, enable the libm feature. The README notes that Float and Real are only available when either std or libm is enabled, and FloatCore is always available.
Which num-traits traits require std or libm?
Float and Real need one of them, and so do MulAdd and MulAddAssign for f32 and f64, along with the implementations of signed and floating point exponents in Pow. FloatCore is always available.
What licence does num-traits use?
Dual licensing at your option: the Apache License, Version 2.0 or the MIT license. The package metadata records it as MIT OR Apache-2.0, and both licence texts are in the repository root as LICENSE-APACHE and LICENSE-MIT.
Where can I find the release notes for num-traits?
The repository has no GitHub releases. Release notes are in RELEASES.md in the repository root, and the current package version recorded in Cargo.toml is 0.2.19.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/rust-num-num-traits)Was this useful?