{"version":3,"sources":["webpack:///path---blog-rust-overflow-94117416bd98b202d62e.js","webpack:///./.cache/json/blog-rust-overflow.json"],"names":["webpackJsonp","366","module","exports","data","site","siteMetadata","title","author","markdownRemark","id","html","frontmatter","date","pathContext","slug","previous","fields"],"mappings":"AAAAA,cAAc,iBAERC,IACA,SAAUC,EAAQC,GCHxBD,EAAAC,SAAkBC,MAAQC,MAAQC,cAAgBC,MAAA,eAAAC,OAAA,kBAAiDC,gBAAmBC,GAAA,4GAAAC,KAAA;AAAo8mCC,aAAgqBL,MAAA,oCAAAM,KAAA,oBAAsEC,aAAgBC,KAAA,uBAAAC,UAA0CC,QAAUF,KAAA,4BAAkCH,aAAgBL,MAAA","file":"path---blog-rust-overflow-94117416bd98b202d62e.js","sourcesContent":["webpackJsonp([40042798607685],{\n\n/***/ 366:\n/***/ (function(module, exports) {\n\n\tmodule.exports = {\"data\":{\"site\":{\"siteMetadata\":{\"title\":\"Valencik.com\",\"author\":\"K.J. Valencik\"}},\"markdownRemark\":{\"id\":\"/home/kvalencik/git/valencik.com/src/pages/blog/rust-overflow/index.md absPath of file >>> MarkdownRemark\",\"html\":\"

One of the core principles of Rust is borrowed from C++—zero-cost abstractions.

\\n
\\n

In general, C++ implementations obey the zero-overhead principle: What you\\ndon’t use, you don’t pay for. And further: What you do use, you couldn’t hand\\ncode any better.

\\n

— Bjarne Stroustrup

\\n
\\n

This permeates much of the ecosystem including traits,\\nborrowing, and iterators. One of the more interesting\\ntrade-offs is the way integer overflow is handled. Fixed size integers in Rust\\nare implemented with two’s complement and may\\noverflow.

\\n

For example, assume with have a u8, an unsigned 8-bit integer. It can\\nrepresent values from 0 to 255.

\\n
\\n
fn main() {\\n\\tlet x = 254u8;\\n\\tprintln!(\\\"{} {:b}\\\", x, x);\\n\\n\\tlet y = x + 1;\\n\\tprintln!(\\\"{} {:b}\\\", y, y);\\n\\n\\tlet z = y + 1;\\n\\tprintln!(\\\"{} {:b}\\\", z, z);\\n}\\n
\\n
\\n

After performing the second addition, the correct result should be 256, but\\nthis exceeds the maximum value of a u8.

\\n

Note: If you are following along, all examples use\\ncargo-script.

\\n
\\n
$ cargo script --debug main.rs\\n254 11111110\\n255 11111111\\nthread 'main' panicked at 'attempt to add with overflow', main.rs:8:10
\\n
\\n

Rust detects the overflow and panics, unwinding the stack and exiting the\\nprocess. Unfortunately, the process of checking arithmetic for overflow is very\\nexpensive. Rust makes a trade-off for performance by disabling overflow checks\\nin release mode.

\\n
\\n
$ cargo script main.rs\\n254 11111110\\n255 11111111\\n0 0
\\n
\\n

In this example, instead of a panic the result wrapped around by truncating the\\nhighest bits. By making this trade-off, hopefully, overflow bugs are caught in\\ntesting without impacting release performance. The specifics of integer overflow\\nin Rust are defined by RFC 560.

\\n

A unit of measure

\\n

Diverging from Rust for a moment, let’s discuss some math. Radians are\\na unit for measuring angles. Radians are defined as the ratio of arc length to\\nthe radius of a circle. As such, a full turn is equivalent to 2π rad2\\\\pi\\\\ rad2π rad.

\\n\\n2π rad=360°2\\\\pi\\\\ rad = 360\\\\degree2π rad=360°\\n

Since angles are periodic by nature, the range of possible values is limited\\nsuch that for any angle α\\\\alphaα

\\n\\n0α <2π0 \\\\leq \\\\alpha\\\\ \\\\lt 2\\\\pi0α <2π\\n

Let’s define a new unit of measure for angles. We define the unit as a fraction\\nof a radian.

\\n\\n2π rad=65536 unit0 unit=65536 unit\\\\begin{aligned}\\n2\\\\pi\\\\ rad = 65536\\\\ unit\\\\\\\\\\n0\\\\ unit = 65536\\\\ unit\\n\\\\end{aligned}2π rad=65536 unit0 unit=65536 unit\\n

Great! We’ve defined a new unit and we can convert to and from an SI\\nunit. Now what?

\\n

Eureka

\\n

A keen eye will have noticed the power of 2. If we map our angles to discrete\\nunits, the maximum value is the same as an unsigned 16-bit integer (u16).

\\n\\n216=655362^{16} = 65536216=65536\\n\\n{αZ:0α<65536}\\\\{{\\\\alpha \\\\in \\\\mathbb Z: 0 \\\\le \\\\alpha \\\\lt 65536}\\\\}{αZ:0α<65536}\\n

This is a very neat property. We have mapped the periodic nature of angles to\\nthe overflow mechanics of two’s compliment arithmetic. This allows for some\\noptimizations. For example, comparing two angles for equality.

\\n

Two angles α\\\\alphaα and β\\\\betaβ are equal, α=β\\\\alpha = \\\\betaα=β, if and only if\\nthere exists some xZx \\\\in \\\\mathbb ZxZ such that xα=βx \\\\cdot \\\\alpha = \\\\betaxα=β or\\nα=xβ\\\\alpha = x \\\\cdot \\\\betaα=xβ.

\\n

Typically this requires division and comparing against some ϵ\\\\epsilonϵ error\\nmargin in the case of floats. Instead, we can simply compare their values.

\\n
\\n
fn main() {\\n\\tlet x = 0u16;\\n\\tlet y = x + 65535 + 1;\\n\\n\\tprintln!(\\\"{}\\\", x == y);\\n}\\n
\\n
\\n
\\n
$ cargo script --debug main.rs\\nthread 'main' panicked at 'attempt to add with overflow', main.rs:3:10
\\n
\\n

Uh, oh. That’s not what we wanted.

\\n

Controlling the flow

\\n

Rust is preventing us from performing exactly the operation we want—addition\\nwith overflow. For precisely this purpose, Rust provides wrapping_ methods.\\nThe wrapping_add method on u16 will sum the two numbers with\\nwrapping on overflow.

\\n
\\n
fn main() {\\n\\tlet x = 0u16;\\n\\tlet y = x.wrapping_add(65535).wrapping_add(1);\\n\\n\\tprintln!(\\\"{}\\\", x == y);\\n}\\n
\\n
\\n
\\n
$ cargo script --debug main.rs\\ntrue
\\n
\\n

Great! Our code is working again, but we’ve lost the ergonomics of code that\\nlooks similar to the mathematical operations we want to perform. Rust provides\\noperator overloading via the std::ops traits. We can follow the\\nnewtype idiom and implement the std::ops::Add trait on\\nthat.

\\n
\\n
use std::ops::Add;\\n\\n#[derive(Clone, Copy, PartialEq)]\\nstruct Angle(u16);\\n\\nimpl Add for Angle {\\n\\ttype Output = Angle;\\n\\n\\tfn add(self, rhs: Self::Output) -> Self::Output {\\n\\t\\tAngle(self.0.wrapping_add(rhs.0))\\n\\t}\\n}\\n\\nfn main() {\\n\\tlet x = Angle(0u16);\\n\\tlet y = x + Angle(65535) + Angle(1);\\n\\n\\tprintln!(\\\"{}\\\", x == y);\\n}\\n
\\n
\\n

In addition to providing a struct to impl, the newtype pattern is useful for\\nensuring correctness. For example, the compiler prevents us from accidentally\\nadding our Angle type to a simple u16 which may represent a different\\nscale.

\\n
\\n
fn main() {\\n\\tlet x = Angle(0u16);\\n\\tlet y = 65535u16; // Represents 180 deg instead of 360 deg\\n\\tlet z = x + y + Angle(1);\\n\\n\\tprintln!(\\\"{}\\\", x == z);\\n}\\n
\\n
\\n
\\n
error[E0308]: mismatched types\\n  --> main.rs:17:14\\n   |\\n17 |     let z = x + y + Angle(1);\\n   |                 ^\\n   |                 |\\n   |                 expected struct `Angle`, found u16\\n   |                 help: try using a variant of the expected type: `Angle(y)`\\n   |\\n   = note: expected type `Angle`\\n              found type `u16`
\\n
\\n

Wrapping

\\n

We likely need to support other arithmetic operations besides addition. It can\\nget tedious to implement each of these traits on Angle. Fortunately, this was\\nconsidered as part of the RFC. std::num::Wrapping<T> is a generic\\nstruct with specialized implementation of many arithmetic traits.

\\n

We can replace our Angle struct with Wrapping and get operator overloading\\nwith wrapping on overflow for free!

\\n
\\n
use std::num::Wrapping;\\n\\nfn main() {\\n\\tlet x = Wrapping(0u16)\\n\\tlet y = Wrapping(65535u16);\\n\\tlet z = x - Wrapping(1);\\n\\n\\tprintln!(\\\"{}\\\", y == z);\\n}\\n
\\n
\\n
\\n
$ cargo script --debug main.rs\\ntrue
\\n
\\n

Going Further

\\n

When switching from the Angle newtype to the built-in Wrapping struct we\\ntraded the type checking validation of our angle units to eliminate the\\nboilerplate of lots of traits impls. This isn’t an ideal trade-off.

\\n

It would be great if Rust included something analogous to Haskell’s\\nGeneralisedNewtypeDeriving. This extension allows\\nderiving any traits implemented by the enclosed type. At the time of this\\nwriting, Rust does not have anything this powerful. But, the macro system can\\ncome close for this use case.

\\n

The derive_more crate provides procedural\\nmacros for deriving common traits by inferring an\\nimplementation from the shape of the data. This works fairly well for simple\\ntypes.

\\n
\\n
//! ```cargo\\n//! [dependencies]\\n//! derive_more = \\\"0.7\\\"\\n//! ```\\n\\n#[macro_use]\\nextern crate derive_more;\\n\\nuse std::num::Wrapping;\\n\\n// Use the `derive_more` crate to derive `Add` and `Sub`!\\n#[derive(PartialEq, Clone, Copy, Add, Sub)]\\nstruct Angle(Wrapping<u16>);\\n\\n// Implement `From` for our newtype to create an `Angle` directly from a `u16`\\nimpl From<u16> for Angle {\\n\\tfn from(n: u16) -> Self {\\n\\t\\tAngle(Wrapping(n))\\n\\t}\\n}\\n\\nfn main() {\\n\\tlet x = Angle::from(0);\\n\\tlet y = Angle::from(65535);\\n\\n\\t// The `From` trait provides `into`. The type can be inferred.\\n\\tlet z = x + x - 1.into();\\n\\n\\tprintln!(\\\"{}\\\", y == z);\\n}\\n
\\n
\\n
\\n
$ cargo script --debug main.rs\\ntrue
\\n
\\n

We wrap the Wrapping struct in our newtype and use derive_more to derive an\\nimpl for Sub on Angle. We manually implement From to make it easier to\\nget a new Angle directly from a u16.

\\n

I enjoyed delving into the various abstractions that rust provides and the\\ndecisions and trade-offs that language makes. I hope you learned something\\ninteresting as well!

\",\"frontmatter\":{\"title\":\"Radians and Rust Integer Overflow\",\"date\":\"March 08, 2018\"}}},\"pathContext\":{\"slug\":\"/blog/rust-overflow/\",\"previous\":{\"fields\":{\"slug\":\"/blog/extending-promise/\"},\"frontmatter\":{\"title\":\"Extending Promise\"}}}}\n\n/***/ })\n\n});\n\n\n// WEBPACK FOOTER //\n// path---blog-rust-overflow-94117416bd98b202d62e.js","module.exports = {\"data\":{\"site\":{\"siteMetadata\":{\"title\":\"Valencik.com\",\"author\":\"K.J. Valencik\"}},\"markdownRemark\":{\"id\":\"/home/kvalencik/git/valencik.com/src/pages/blog/rust-overflow/index.md absPath of file >>> MarkdownRemark\",\"html\":\"

One of the core principles of Rust is borrowed from C++—zero-cost abstractions.

\\n
\\n

In general, C++ implementations obey the zero-overhead principle: What you\\ndon’t use, you don’t pay for. And further: What you do use, you couldn’t hand\\ncode any better.

\\n

— Bjarne Stroustrup

\\n
\\n

This permeates much of the ecosystem including traits,\\nborrowing, and iterators. One of the more interesting\\ntrade-offs is the way integer overflow is handled. Fixed size integers in Rust\\nare implemented with two’s complement and may\\noverflow.

\\n

For example, assume with have a u8, an unsigned 8-bit integer. It can\\nrepresent values from 0 to 255.

\\n
\\n
fn main() {\\n\\tlet x = 254u8;\\n\\tprintln!(\\\"{} {:b}\\\", x, x);\\n\\n\\tlet y = x + 1;\\n\\tprintln!(\\\"{} {:b}\\\", y, y);\\n\\n\\tlet z = y + 1;\\n\\tprintln!(\\\"{} {:b}\\\", z, z);\\n}\\n
\\n
\\n

After performing the second addition, the correct result should be 256, but\\nthis exceeds the maximum value of a u8.

\\n

Note: If you are following along, all examples use\\ncargo-script.

\\n
\\n
$ cargo script --debug main.rs\\n254 11111110\\n255 11111111\\nthread 'main' panicked at 'attempt to add with overflow', main.rs:8:10
\\n
\\n

Rust detects the overflow and panics, unwinding the stack and exiting the\\nprocess. Unfortunately, the process of checking arithmetic for overflow is very\\nexpensive. Rust makes a trade-off for performance by disabling overflow checks\\nin release mode.

\\n
\\n
$ cargo script main.rs\\n254 11111110\\n255 11111111\\n0 0
\\n
\\n

In this example, instead of a panic the result wrapped around by truncating the\\nhighest bits. By making this trade-off, hopefully, overflow bugs are caught in\\ntesting without impacting release performance. The specifics of integer overflow\\nin Rust are defined by RFC 560.

\\n

A unit of measure

\\n

Diverging from Rust for a moment, let’s discuss some math. Radians are\\na unit for measuring angles. Radians are defined as the ratio of arc length to\\nthe radius of a circle. As such, a full turn is equivalent to 2π rad2\\\\pi\\\\ rad2π rad.

\\n\\n2π rad=360°2\\\\pi\\\\ rad = 360\\\\degree2π rad=360°\\n

Since angles are periodic by nature, the range of possible values is limited\\nsuch that for any angle α\\\\alphaα

\\n\\n0α <2π0 \\\\leq \\\\alpha\\\\ \\\\lt 2\\\\pi0α <2π\\n

Let’s define a new unit of measure for angles. We define the unit as a fraction\\nof a radian.

\\n\\n2π rad=65536 unit0 unit=65536 unit\\\\begin{aligned}\\n2\\\\pi\\\\ rad = 65536\\\\ unit\\\\\\\\\\n0\\\\ unit = 65536\\\\ unit\\n\\\\end{aligned}2π rad=65536 unit0 unit=65536 unit\\n

Great! We’ve defined a new unit and we can convert to and from an SI\\nunit. Now what?

\\n

Eureka

\\n

A keen eye will have noticed the power of 2. If we map our angles to discrete\\nunits, the maximum value is the same as an unsigned 16-bit integer (u16).

\\n\\n216=655362^{16} = 65536216=65536\\n\\n{αZ:0α<65536}\\\\{{\\\\alpha \\\\in \\\\mathbb Z: 0 \\\\le \\\\alpha \\\\lt 65536}\\\\}{αZ:0α<65536}\\n

This is a very neat property. We have mapped the periodic nature of angles to\\nthe overflow mechanics of two’s compliment arithmetic. This allows for some\\noptimizations. For example, comparing two angles for equality.

\\n

Two angles α\\\\alphaα and β\\\\betaβ are equal, α=β\\\\alpha = \\\\betaα=β, if and only if\\nthere exists some xZx \\\\in \\\\mathbb ZxZ such that xα=βx \\\\cdot \\\\alpha = \\\\betaxα=β or\\nα=xβ\\\\alpha = x \\\\cdot \\\\betaα=xβ.

\\n

Typically this requires division and comparing against some ϵ\\\\epsilonϵ error\\nmargin in the case of floats. Instead, we can simply compare their values.

\\n
\\n
fn main() {\\n\\tlet x = 0u16;\\n\\tlet y = x + 65535 + 1;\\n\\n\\tprintln!(\\\"{}\\\", x == y);\\n}\\n
\\n
\\n
\\n
$ cargo script --debug main.rs\\nthread 'main' panicked at 'attempt to add with overflow', main.rs:3:10
\\n
\\n

Uh, oh. That’s not what we wanted.

\\n

Controlling the flow

\\n

Rust is preventing us from performing exactly the operation we want—addition\\nwith overflow. For precisely this purpose, Rust provides wrapping_ methods.\\nThe wrapping_add method on u16 will sum the two numbers with\\nwrapping on overflow.

\\n
\\n
fn main() {\\n\\tlet x = 0u16;\\n\\tlet y = x.wrapping_add(65535).wrapping_add(1);\\n\\n\\tprintln!(\\\"{}\\\", x == y);\\n}\\n
\\n
\\n
\\n
$ cargo script --debug main.rs\\ntrue
\\n
\\n

Great! Our code is working again, but we’ve lost the ergonomics of code that\\nlooks similar to the mathematical operations we want to perform. Rust provides\\noperator overloading via the std::ops traits. We can follow the\\nnewtype idiom and implement the std::ops::Add trait on\\nthat.

\\n
\\n
use std::ops::Add;\\n\\n#[derive(Clone, Copy, PartialEq)]\\nstruct Angle(u16);\\n\\nimpl Add for Angle {\\n\\ttype Output = Angle;\\n\\n\\tfn add(self, rhs: Self::Output) -> Self::Output {\\n\\t\\tAngle(self.0.wrapping_add(rhs.0))\\n\\t}\\n}\\n\\nfn main() {\\n\\tlet x = Angle(0u16);\\n\\tlet y = x + Angle(65535) + Angle(1);\\n\\n\\tprintln!(\\\"{}\\\", x == y);\\n}\\n
\\n
\\n

In addition to providing a struct to impl, the newtype pattern is useful for\\nensuring correctness. For example, the compiler prevents us from accidentally\\nadding our Angle type to a simple u16 which may represent a different\\nscale.

\\n
\\n
fn main() {\\n\\tlet x = Angle(0u16);\\n\\tlet y = 65535u16; // Represents 180 deg instead of 360 deg\\n\\tlet z = x + y + Angle(1);\\n\\n\\tprintln!(\\\"{}\\\", x == z);\\n}\\n
\\n
\\n
\\n
error[E0308]: mismatched types\\n  --> main.rs:17:14\\n   |\\n17 |     let z = x + y + Angle(1);\\n   |                 ^\\n   |                 |\\n   |                 expected struct `Angle`, found u16\\n   |                 help: try using a variant of the expected type: `Angle(y)`\\n   |\\n   = note: expected type `Angle`\\n              found type `u16`
\\n
\\n

Wrapping

\\n

We likely need to support other arithmetic operations besides addition. It can\\nget tedious to implement each of these traits on Angle. Fortunately, this was\\nconsidered as part of the RFC. std::num::Wrapping<T> is a generic\\nstruct with specialized implementation of many arithmetic traits.

\\n

We can replace our Angle struct with Wrapping and get operator overloading\\nwith wrapping on overflow for free!

\\n
\\n
use std::num::Wrapping;\\n\\nfn main() {\\n\\tlet x = Wrapping(0u16)\\n\\tlet y = Wrapping(65535u16);\\n\\tlet z = x - Wrapping(1);\\n\\n\\tprintln!(\\\"{}\\\", y == z);\\n}\\n
\\n
\\n
\\n
$ cargo script --debug main.rs\\ntrue
\\n
\\n

Going Further

\\n

When switching from the Angle newtype to the built-in Wrapping struct we\\ntraded the type checking validation of our angle units to eliminate the\\nboilerplate of lots of traits impls. This isn’t an ideal trade-off.

\\n

It would be great if Rust included something analogous to Haskell’s\\nGeneralisedNewtypeDeriving. This extension allows\\nderiving any traits implemented by the enclosed type. At the time of this\\nwriting, Rust does not have anything this powerful. But, the macro system can\\ncome close for this use case.

\\n

The derive_more crate provides procedural\\nmacros for deriving common traits by inferring an\\nimplementation from the shape of the data. This works fairly well for simple\\ntypes.

\\n
\\n
//! ```cargo\\n//! [dependencies]\\n//! derive_more = \\\"0.7\\\"\\n//! ```\\n\\n#[macro_use]\\nextern crate derive_more;\\n\\nuse std::num::Wrapping;\\n\\n// Use the `derive_more` crate to derive `Add` and `Sub`!\\n#[derive(PartialEq, Clone, Copy, Add, Sub)]\\nstruct Angle(Wrapping<u16>);\\n\\n// Implement `From` for our newtype to create an `Angle` directly from a `u16`\\nimpl From<u16> for Angle {\\n\\tfn from(n: u16) -> Self {\\n\\t\\tAngle(Wrapping(n))\\n\\t}\\n}\\n\\nfn main() {\\n\\tlet x = Angle::from(0);\\n\\tlet y = Angle::from(65535);\\n\\n\\t// The `From` trait provides `into`. The type can be inferred.\\n\\tlet z = x + x - 1.into();\\n\\n\\tprintln!(\\\"{}\\\", y == z);\\n}\\n
\\n
\\n
\\n
$ cargo script --debug main.rs\\ntrue
\\n
\\n

We wrap the Wrapping struct in our newtype and use derive_more to derive an\\nimpl for Sub on Angle. We manually implement From to make it easier to\\nget a new Angle directly from a u16.

\\n

I enjoyed delving into the various abstractions that rust provides and the\\ndecisions and trade-offs that language makes. I hope you learned something\\ninteresting as well!

\",\"frontmatter\":{\"title\":\"Radians and Rust Integer Overflow\",\"date\":\"March 08, 2018\"}}},\"pathContext\":{\"slug\":\"/blog/rust-overflow/\",\"previous\":{\"fields\":{\"slug\":\"/blog/extending-promise/\"},\"frontmatter\":{\"title\":\"Extending Promise\"}}}}\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/json-loader!./.cache/json/blog-rust-overflow.json\n// module id = 366\n// module chunks = 40042798607685"],"sourceRoot":""}