Skip to content

Commit 9f57996

Browse files
committed
Add Integer::{log,log2,log10} variants
1 parent b6f3cb9 commit 9f57996

File tree

6 files changed

+478
-0
lines changed

6 files changed

+478
-0
lines changed

library/core/src/num/int_macros.rs

+188
Original file line numberDiff line numberDiff line change
@@ -1744,6 +1744,194 @@ macro_rules! int_impl {
17441744
}
17451745
}
17461746

1747+
/// Returns the logarithm of the number with respect to an arbitrary base.
1748+
///
1749+
/// This method may not be optimized owing to implementation details;
1750+
/// `log2` can produce results more efficiently for base 2, and `log10`
1751+
/// can produce results more efficiently for base 10.
1752+
///
1753+
/// # Panics
1754+
///
1755+
/// When the number is zero, or if the base is not at least 2; it
1756+
/// panics in debug mode and the return value is wrapped to 0 in release
1757+
/// mode (the only situation in which the method can return 0).
1758+
///
1759+
/// # Examples
1760+
///
1761+
/// ```
1762+
/// #![feature(int_log)]
1763+
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".log(5), 1);")]
1764+
/// ```
1765+
#[unstable(feature = "int_log", issue = "70887")]
1766+
#[must_use = "this returns the result of the operation, \
1767+
without modifying the original"]
1768+
#[inline]
1769+
#[track_caller]
1770+
#[rustc_inherit_overflow_checks]
1771+
#[allow(arithmetic_overflow)]
1772+
pub const fn log(self, base: Self) -> Self {
1773+
match self.checked_log(base) {
1774+
Some(n) => n,
1775+
None => {
1776+
// In debug builds, trigger a panic on None.
1777+
// This should optimize completely out in release builds.
1778+
let _ = Self::MAX + 1;
1779+
1780+
0
1781+
},
1782+
}
1783+
}
1784+
1785+
/// Returns the base 2 logarithm of the number.
1786+
///
1787+
/// # Panics
1788+
///
1789+
/// When the number is zero it panics in debug mode and the return value
1790+
/// is wrapped to 0 in release mode (the only situation in which the
1791+
/// method can return 0).
1792+
///
1793+
/// # Examples
1794+
///
1795+
/// ```
1796+
/// #![feature(int_log)]
1797+
#[doc = concat!("assert_eq!(2", stringify!($SelfT), ".log2(), 1);")]
1798+
/// ```
1799+
#[unstable(feature = "int_log", issue = "70887")]
1800+
#[must_use = "this returns the result of the operation, \
1801+
without modifying the original"]
1802+
#[inline]
1803+
#[track_caller]
1804+
#[rustc_inherit_overflow_checks]
1805+
#[allow(arithmetic_overflow)]
1806+
pub const fn log2(self) -> Self {
1807+
match self.checked_log2() {
1808+
Some(n) => n,
1809+
None => {
1810+
// In debug builds, trigger a panic on None.
1811+
// This should optimize completely out in release builds.
1812+
let _ = Self::MAX + 1;
1813+
1814+
0
1815+
},
1816+
}
1817+
}
1818+
1819+
/// Returns the base 10 logarithm of the number.
1820+
///
1821+
/// # Panics
1822+
///
1823+
/// When the number is zero it panics in debug mode and the return value
1824+
/// is wrapped to 0 in release mode (the only situation in which the
1825+
/// method can return 0).
1826+
///
1827+
/// # Example
1828+
///
1829+
/// ```
1830+
/// #![feature(int_log)]
1831+
#[doc = concat!("assert_eq!(10", stringify!($SelfT), ".log10(), 1);")]
1832+
/// ```
1833+
#[unstable(feature = "int_log", issue = "70887")]
1834+
#[must_use = "this returns the result of the operation, \
1835+
without modifying the original"]
1836+
#[inline]
1837+
#[track_caller]
1838+
#[rustc_inherit_overflow_checks]
1839+
#[allow(arithmetic_overflow)]
1840+
pub const fn log10(self) -> Self {
1841+
match self.checked_log10() {
1842+
Some(n) => n,
1843+
None => {
1844+
// In debug builds, trigger a panic on None.
1845+
// This should optimize completely out in release builds.
1846+
let _ = Self::MAX + 1;
1847+
1848+
0
1849+
},
1850+
}
1851+
}
1852+
1853+
/// Returns the logarithm of the number with respect to an arbitrary base.
1854+
///
1855+
/// Returns `None` if the number is negative or zero, or if the base is not at least 2.
1856+
///
1857+
/// This method may not be optimized owing to implementation details;
1858+
/// `checked_log2` can produce results more efficiently for base 2, and
1859+
/// `checked_log10` can produce results more efficiently for base 10.
1860+
///
1861+
/// # Examples
1862+
///
1863+
/// ```
1864+
/// #![feature(int_log)]
1865+
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_log(5), Some(1));")]
1866+
/// ```
1867+
#[unstable(feature = "int_log", issue = "70887")]
1868+
#[must_use = "this returns the result of the operation, \
1869+
without modifying the original"]
1870+
#[inline]
1871+
pub const fn checked_log(self, base: Self) -> Option<Self> {
1872+
if self <= 0 || base <= 1 {
1873+
None
1874+
} else {
1875+
let mut n = 0;
1876+
let mut r = self;
1877+
1878+
// Optimization for 128 bit wide integers.
1879+
if Self::BITS == 128 {
1880+
let b = Self::log2(self) / (Self::log2(base) + 1);
1881+
n += b;
1882+
r /= base.pow(b as u32);
1883+
}
1884+
1885+
while r >= base {
1886+
r /= base;
1887+
n += 1;
1888+
}
1889+
Some(n)
1890+
}
1891+
}
1892+
1893+
/// Returns the base 2 logarithm of the number.
1894+
///
1895+
/// Returns `None` if the number is negative or zero.
1896+
///
1897+
/// # Examples
1898+
///
1899+
/// ```
1900+
/// #![feature(int_log)]
1901+
#[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_log2(), Some(1));")]
1902+
/// ```
1903+
#[unstable(feature = "int_log", issue = "70887")]
1904+
#[must_use = "this returns the result of the operation, \
1905+
without modifying the original"]
1906+
#[inline]
1907+
pub const fn checked_log2(self) -> Option<Self> {
1908+
if self <= 0 {
1909+
None
1910+
} else {
1911+
// SAFETY: We just checked that this number is positive
1912+
let log = (Self::BITS - 1) as Self - unsafe { intrinsics::ctlz_nonzero(self) };
1913+
Some(log)
1914+
}
1915+
}
1916+
1917+
/// Returns the base 10 logarithm of the number.
1918+
///
1919+
/// Returns `None` if the number is negative or zero.
1920+
///
1921+
/// # Example
1922+
///
1923+
/// ```
1924+
/// #![feature(int_log)]
1925+
#[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_log10(), Some(1));")]
1926+
/// ```
1927+
#[unstable(feature = "int_log", issue = "70887")]
1928+
#[must_use = "this returns the result of the operation, \
1929+
without modifying the original"]
1930+
#[inline]
1931+
pub const fn checked_log10(self) -> Option<Self> {
1932+
self.checked_log(10)
1933+
}
1934+
17471935
/// Computes the absolute value of `self`.
17481936
///
17491937
/// # Overflow behavior

library/core/src/num/uint_macros.rs

+188
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,194 @@ macro_rules! uint_impl {
634634
}
635635
}
636636

637+
/// Returns the logarithm of the number with respect to an arbitrary base.
638+
///
639+
/// This method may not be optimized owing to implementation details;
640+
/// `log2` can produce results more efficiently for base 2, and `log10`
641+
/// can produce results more efficiently for base 10.
642+
///
643+
/// # Panics
644+
///
645+
/// When the number is negative, zero, or if the base is not at least 2;
646+
/// it panics in debug mode and the return value is wrapped to 0 in
647+
/// release mode (the only situation in which the method can return 0).
648+
///
649+
/// # Examples
650+
///
651+
/// ```
652+
/// #![feature(int_log)]
653+
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".log(5), 1);")]
654+
/// ```
655+
#[unstable(feature = "int_log", issue = "70887")]
656+
#[must_use = "this returns the result of the operation, \
657+
without modifying the original"]
658+
#[inline]
659+
#[track_caller]
660+
#[rustc_inherit_overflow_checks]
661+
#[allow(arithmetic_overflow)]
662+
pub const fn log(self, base: Self) -> Self {
663+
match self.checked_log(base) {
664+
Some(n) => n,
665+
None => {
666+
// In debug builds, trigger a panic on None.
667+
// This should optimize completely out in release builds.
668+
let _ = Self::MAX + 1;
669+
670+
0
671+
},
672+
}
673+
}
674+
675+
/// Returns the base 2 logarithm of the number.
676+
///
677+
/// # Panics
678+
///
679+
/// When the number is negative or zero it panics in debug mode and
680+
/// the return value is wrapped to 0 in release mode (the only situation in
681+
/// which the method can return 0).
682+
///
683+
/// # Examples
684+
///
685+
/// ```
686+
/// #![feature(int_log)]
687+
#[doc = concat!("assert_eq!(2", stringify!($SelfT), ".log2(), 1);")]
688+
/// ```
689+
#[unstable(feature = "int_log", issue = "70887")]
690+
#[must_use = "this returns the result of the operation, \
691+
without modifying the original"]
692+
#[inline]
693+
#[track_caller]
694+
#[rustc_inherit_overflow_checks]
695+
#[allow(arithmetic_overflow)]
696+
pub const fn log2(self) -> Self {
697+
match self.checked_log2() {
698+
Some(n) => n,
699+
None => {
700+
// In debug builds, trigger a panic on None.
701+
// This should optimize completely out in release builds.
702+
let _ = Self::MAX + 1;
703+
704+
0
705+
},
706+
}
707+
}
708+
709+
/// Returns the base 10 logarithm of the number.
710+
///
711+
/// # Panics
712+
///
713+
/// When the number is negative or zero it panics in debug mode and the
714+
/// return value is wrapped to 0 in release mode (the only situation in
715+
/// which the method can return 0).
716+
///
717+
/// # Example
718+
///
719+
/// ```
720+
/// #![feature(int_log)]
721+
#[doc = concat!("assert_eq!(10", stringify!($SelfT), ".log10(), 1);")]
722+
/// ```
723+
#[unstable(feature = "int_log", issue = "70887")]
724+
#[must_use = "this returns the result of the operation, \
725+
without modifying the original"]
726+
#[inline]
727+
#[track_caller]
728+
#[rustc_inherit_overflow_checks]
729+
#[allow(arithmetic_overflow)]
730+
pub const fn log10(self) -> Self {
731+
match self.checked_log10() {
732+
Some(n) => n,
733+
None => {
734+
// In debug builds, trigger a panic on None.
735+
// This should optimize completely out in release builds.
736+
let _ = Self::MAX + 1;
737+
738+
0
739+
},
740+
}
741+
}
742+
743+
/// Returns the logarithm of the number with respect to an arbitrary base.
744+
///
745+
/// Returns `None` if the number is zero, or if the base is not at least 2.
746+
///
747+
/// This method may not be optimized owing to implementation details;
748+
/// `checked_log2` can produce results more efficiently for base 2, and
749+
/// `checked_log10` can produce results more efficiently for base 10.
750+
///
751+
/// # Examples
752+
///
753+
/// ```
754+
/// #![feature(int_log)]
755+
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_log(5), Some(1));")]
756+
/// ```
757+
#[unstable(feature = "int_log", issue = "70887")]
758+
#[must_use = "this returns the result of the operation, \
759+
without modifying the original"]
760+
#[inline]
761+
pub const fn checked_log(self, base: Self) -> Option<Self> {
762+
if self <= 0 || base <= 1 {
763+
None
764+
} else {
765+
let mut n = 0;
766+
let mut r = self;
767+
768+
// Optimization for 128 bit wide integers.
769+
if Self::BITS == 128 {
770+
let b = Self::log2(self) / (Self::log2(base) + 1);
771+
n += b;
772+
r /= base.pow(b as u32);
773+
}
774+
775+
while r >= base {
776+
r /= base;
777+
n += 1;
778+
}
779+
Some(n)
780+
}
781+
}
782+
783+
/// Returns the base 2 logarithm of the number.
784+
///
785+
/// Returns `None` if the number is zero.
786+
///
787+
/// # Examples
788+
///
789+
/// ```
790+
/// #![feature(int_log)]
791+
#[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_log2(), Some(1));")]
792+
/// ```
793+
#[unstable(feature = "int_log", issue = "70887")]
794+
#[must_use = "this returns the result of the operation, \
795+
without modifying the original"]
796+
#[inline]
797+
pub const fn checked_log2(self) -> Option<Self> {
798+
if self <= 0 {
799+
None
800+
} else {
801+
// SAFETY: We just checked that this number is positive
802+
let log = (Self::BITS - 1) as Self - unsafe { intrinsics::ctlz_nonzero(self) };
803+
Some(log)
804+
}
805+
}
806+
807+
/// Returns the base 10 logarithm of the number.
808+
///
809+
/// Returns `None` if the number is zero.
810+
///
811+
/// # Examples
812+
///
813+
/// ```
814+
/// #![feature(int_log)]
815+
#[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_log10(), Some(1));")]
816+
/// ```
817+
#[unstable(feature = "int_log", issue = "70887")]
818+
#[must_use = "this returns the result of the operation, \
819+
without modifying the original"]
820+
#[inline]
821+
pub const fn checked_log10(self) -> Option<Self> {
822+
self.checked_log(10)
823+
}
824+
637825
/// Checked negation. Computes `-self`, returning `None` unless `self ==
638826
/// 0`.
639827
///

library/core/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#![feature(try_trait_v2)]
4646
#![feature(slice_internals)]
4747
#![feature(slice_partition_dedup)]
48+
#![feature(int_log)]
4849
#![feature(iter_advance_by)]
4950
#![feature(iter_partition_in_place)]
5051
#![feature(iter_intersperse)]

0 commit comments

Comments
 (0)