-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7f7cc8c
commit 5c22176
Showing
88 changed files
with
582 additions
and
82 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
1 change: 1 addition & 0 deletions
1
...6kOX2X7D8V4/posts/0xffffffffffffffffn-uint64-hack-to-decrement-by-one-using-addition.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"pageProps":{"article":{"title":"0xffffffffffffffffn: uint64 hack to decrement by one using addition","layout":"posts","slug":"0xffffffffffffffffn-uint64-hack-to-decrement-by-one-using-addition","draft":false,"frontMatter":{"title":"0xffffffffffffffffn: uint64 hack to decrement by one using addition","publishedDate":"2023-10-12T10:15:02Z","tags":["Deno","Deno KV","TypeScript","JavaScript","Binary Arithmetic"],"description":"","disableComments":false},"rawContent":"\n## Introduction\n\nIn the world of software development, there are often clever tricks and hacks that developers use to solve specific problems. One such trick involves using `uint64` (unsigned 64-bit integer) arithmetic to subtract 1 from a number without actually using subtraction. This might sound confusing at first, but with a simple analogy and some examples, it becomes clear!\n\n## The Toy Cash Register Analogy\n\nImagine a child's toy cash register that can only count up to `9`. When it reaches `9`, and you try adding `1` more, it wraps around and returns to `0`. Now, if this toy didn't have a subtraction button, how could you subtract `1` from any number? The trick is to add `9`! When you add `9`, you essentially go full circle and land `1` number behind where you started.\n\n## The Technical Explanation\n\nIn binary arithmetic, numbers are represented using bits. A `uint64` number uses 64 bits. When you add two numbers and the result is too big to fit in 64 bits, it wraps around, similar to our toy cash register.\n\nThe magic number `0xffffffffffffffffn` (which represents all `1`s in binary for a 64-bit number) acts like the number `9` in our analogy. When you add this number to any `uint64`, it's equivalent to subtracting `1`.\n\n| Bit Position: | 63-56 | 55-48 | 47-40 | 39-32 | 31-24 | 23-16 | 15-8 | 7-0 |\n| -------------------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |\n| Previous Number: 3 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000011 |\n| Magic Number to add: | 11111111 | 11111111 | 11111111 | 11111111 | 11111111 | 11111111 | 11111111 | 11111111 |\n| Result: 2 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000010 |\n\n### Example Code\n\n```javascript\n// Convention for BigInts is to add an \"n\" at the end.\nconst previousNumber = 3n;\n\n// Hexadecimal representation of 64-bit magic number.\nconst magicNumber = 0xffffffffffffffffn;\n\n// Convert to 64-bit unsigned integer.\nconst result = BigInt.asUintN(64, previousNumber + magicNumber);\n\nconsole.log(result); // This will be 2n.\n```\n\n## Why is this Useful?\n\nIn the realm of programming, there are instances where certain operations, like subtraction, might be restricted due to system constraints. This \"magic number\" trick offers a clever workaround for such situations.\n\nTake, for example, [Deno KV](https://deno.com/kv). This key-value storage system in Deno provides an atomic [sum](https://docs.deno.com/kv/manual/operations#sum) operation, allowing you to add two [`Deno.KvU64`](https://deno.land/[email protected]?s=Deno.KvU64&unstable=) values. This is particularly handy for incrementing numeric counters in an [ACID-compliant way](https://en.wikipedia.org/wiki/ACID). However, there's a catch: you can't directly decrement a value using this method since `Deno.KvU64` requires a positive number in the construction.\n\nHere's how you'd typically increment a counter:\n\n```typescript\nawait kv\n .atomic()\n .mutate({\n type: 'sum',\n key: ['users_count'],\n value: new Deno.KvU64(1n)\n })\n .commit();\n```\n\nBut what if you wanted to decrease this counter? Enter our magic number trick. By using the magic number `0xffffffffffffffffn`, you can effectively subtract from the counter:\n\n```typescript\nawait kv\n .atomic()\n .mutate({\n type: 'sum',\n key: ['users_count'],\n value: new Deno.KvU64(0xffffffffffffffffn)\n })\n .commit();\n```\n\nIn essence, this approach leverages the properties of binary arithmetic to bypass system constraints. Pretty cool, right?\n\n## Conclusion\n\nUnderstanding the underlying principles of binary arithmetic can open the door to many clever tricks in programming. The `uint64` subtraction trick is just one example. Hopefully, you can find efficient solutions to complex problems by understanding and applying these concepts to your following projects.\n","excerpt":"\n## Introduction\n\nIn the world of software development, there are often clever tricks and hacks that developers use to solve specific problems. One such trick involves using `uint64` (unsigned 64-bit integer) arithmetic to subtract 1 from a number without actually using subtraction. This might sound...","serializedContent":{"compiledSource":"var u=Object.defineProperty,m=Object.defineProperties;var c=Object.getOwnPropertyDescriptors;var r=Object.getOwnPropertySymbols;var o=Object.prototype.hasOwnProperty,l=Object.prototype.propertyIsEnumerable;var p=(t,n,a)=>n in t?u(t,n,{enumerable:!0,configurable:!0,writable:!0,value:a}):t[n]=a,e=(t,n)=>{for(var a in n||(n={}))o.call(n,a)&&p(t,a,n[a]);if(r)for(var a of r(n))l.call(n,a)&&p(t,a,n[a]);return t},d=(t,n)=>m(t,c(n));var s=(t,n)=>{var a={};for(var i in t)o.call(t,i)&&n.indexOf(i)<0&&(a[i]=t[i]);if(t!=null&&r)for(var i of r(t))n.indexOf(i)<0&&l.call(t,i)&&(a[i]=t[i]);return a};const layoutProps={},MDXLayout=\"wrapper\";function MDXContent(a){var i=a,{components:t}=i,n=s(i,[\"components\"]);return mdx(MDXLayout,d(e(e({},layoutProps),n),{components:t,mdxType:\"MDXLayout\"}),mdx(\"h2\",e({},{id:\"introduction\"}),\"Introduction\"),mdx(\"p\",null,\"In the world of software development, there are often clever tricks and hacks that developers use to solve specific problems. One such trick involves using \",mdx(\"inlineCode\",{parentName:\"p\"},\"uint64\"),\" (unsigned 64-bit integer) arithmetic to subtract 1 from a number without actually using subtraction. This might sound confusing at first, but with a simple analogy and some examples, it becomes clear!\"),mdx(\"h2\",e({},{id:\"the-toy-cash-register-analogy\"}),\"The Toy Cash Register Analogy\"),mdx(\"p\",null,\"Imagine a child's toy cash register that can only count up to \",mdx(\"inlineCode\",{parentName:\"p\"},\"9\"),\". When it reaches \",mdx(\"inlineCode\",{parentName:\"p\"},\"9\"),\", and you try adding \",mdx(\"inlineCode\",{parentName:\"p\"},\"1\"),\" more, it wraps around and returns to \",mdx(\"inlineCode\",{parentName:\"p\"},\"0\"),\". Now, if this toy didn't have a subtraction button, how could you subtract \",mdx(\"inlineCode\",{parentName:\"p\"},\"1\"),\" from any number? The trick is to add \",mdx(\"inlineCode\",{parentName:\"p\"},\"9\"),\"! When you add \",mdx(\"inlineCode\",{parentName:\"p\"},\"9\"),\", you essentially go full circle and land \",mdx(\"inlineCode\",{parentName:\"p\"},\"1\"),\" number behind where you started.\"),mdx(\"h2\",e({},{id:\"the-technical-explanation\"}),\"The Technical Explanation\"),mdx(\"p\",null,\"In binary arithmetic, numbers are represented using bits. A \",mdx(\"inlineCode\",{parentName:\"p\"},\"uint64\"),\" number uses 64 bits. When you add two numbers and the result is too big to fit in 64 bits, it wraps around, similar to our toy cash register.\"),mdx(\"p\",null,\"The magic number \",mdx(\"inlineCode\",{parentName:\"p\"},\"0xffffffffffffffffn\"),\" (which represents all \",mdx(\"inlineCode\",{parentName:\"p\"},\"1\"),\"s in binary for a 64-bit number) acts like the number \",mdx(\"inlineCode\",{parentName:\"p\"},\"9\"),\" in our analogy. When you add this number to any \",mdx(\"inlineCode\",{parentName:\"p\"},\"uint64\"),\", it's equivalent to subtracting \",mdx(\"inlineCode\",{parentName:\"p\"},\"1\"),\".\"),mdx(\"table\",null,mdx(\"thead\",{parentName:\"table\"},mdx(\"tr\",{parentName:\"thead\"},mdx(\"th\",e({parentName:\"tr\"},{align:null}),\"Bit Position:\"),mdx(\"th\",e({parentName:\"tr\"},{align:null}),\"63-56\"),mdx(\"th\",e({parentName:\"tr\"},{align:null}),\"55-48\"),mdx(\"th\",e({parentName:\"tr\"},{align:null}),\"47-40\"),mdx(\"th\",e({parentName:\"tr\"},{align:null}),\"39-32\"),mdx(\"th\",e({parentName:\"tr\"},{align:null}),\"31-24\"),mdx(\"th\",e({parentName:\"tr\"},{align:null}),\"23-16\"),mdx(\"th\",e({parentName:\"tr\"},{align:null}),\"15-8\"),mdx(\"th\",e({parentName:\"tr\"},{align:null}),\"7-0\"))),mdx(\"tbody\",{parentName:\"table\"},mdx(\"tr\",{parentName:\"tbody\"},mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"Previous Number: 3\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"00000000\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"00000000\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"00000000\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"00000000\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"00000000\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"00000000\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"00000000\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"00000011\")),mdx(\"tr\",{parentName:\"tbody\"},mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"Magic Number to add:\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"11111111\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"11111111\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"11111111\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"11111111\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"11111111\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"11111111\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"11111111\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"11111111\")),mdx(\"tr\",{parentName:\"tbody\"},mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"Result: 2\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"00000000\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"00000000\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"00000000\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"00000000\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"00000000\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"00000000\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"00000000\"),mdx(\"td\",e({parentName:\"tr\"},{align:null}),\"00000010\")))),mdx(\"h3\",e({},{id:\"example-code\"}),\"Example Code\"),mdx(\"pre\",null,mdx(\"code\",e({parentName:\"pre\"},{className:\"language-javascript\"}),`// Convention for BigInts is to add an \"n\" at the end.\nconst previousNumber = 3n;\n\n// Hexadecimal representation of 64-bit magic number.\nconst magicNumber = 0xffffffffffffffffn;\n\n// Convert to 64-bit unsigned integer.\nconst result = BigInt.asUintN(64, previousNumber + magicNumber);\n\nconsole.log(result); // This will be 2n.\n`)),mdx(\"h2\",e({},{id:\"why-is-this-useful\"}),\"Why is this Useful?\"),mdx(\"p\",null,'In the realm of programming, there are instances where certain operations, like subtraction, might be restricted due to system constraints. This \"magic number\" trick offers a clever workaround for such situations.'),mdx(\"p\",null,\"Take, for example, \",mdx(\"a\",e({parentName:\"p\"},{href:\"https://deno.com/kv\"}),\"Deno KV\"),\". This key-value storage system in Deno provides an atomic \",mdx(\"a\",e({parentName:\"p\"},{href:\"https://docs.deno.com/kv/manual/operations#sum\"}),\"sum\"),\" operation, allowing you to add two \",mdx(\"a\",e({parentName:\"p\"},{href:\"https://deno.land/[email protected]?s=Deno.KvU64&unstable=\"}),mdx(\"inlineCode\",{parentName:\"a\"},\"Deno.KvU64\")),\" values. This is particularly handy for incrementing numeric counters in an \",mdx(\"a\",e({parentName:\"p\"},{href:\"https://en.wikipedia.org/wiki/ACID\"}),\"ACID-compliant way\"),\". However, there's a catch: you can't directly decrement a value using this method since \",mdx(\"inlineCode\",{parentName:\"p\"},\"Deno.KvU64\"),\" requires a positive number in the construction.\"),mdx(\"p\",null,\"Here's how you'd typically increment a counter:\"),mdx(\"pre\",null,mdx(\"code\",e({parentName:\"pre\"},{className:\"language-typescript\"}),`await kv\n .atomic()\n .mutate({\n type: 'sum',\n key: ['users_count'],\n value: new Deno.KvU64(1n)\n })\n .commit();\n`)),mdx(\"p\",null,\"But what if you wanted to decrease this counter? Enter our magic number trick. By using the magic number \",mdx(\"inlineCode\",{parentName:\"p\"},\"0xffffffffffffffffn\"),\", you can effectively subtract from the counter:\"),mdx(\"pre\",null,mdx(\"code\",e({parentName:\"pre\"},{className:\"language-typescript\"}),`await kv\n .atomic()\n .mutate({\n type: 'sum',\n key: ['users_count'],\n value: new Deno.KvU64(0xffffffffffffffffn)\n })\n .commit();\n`)),mdx(\"p\",null,\"In essence, this approach leverages the properties of binary arithmetic to bypass system constraints. Pretty cool, right?\"),mdx(\"h2\",e({},{id:\"conclusion\"}),\"Conclusion\"),mdx(\"p\",null,\"Understanding the underlying principles of binary arithmetic can open the door to many clever tricks in programming. The \",mdx(\"inlineCode\",{parentName:\"p\"},\"uint64\"),\" subtraction trick is just one example. Hopefully, you can find efficient solutions to complex problems by understanding and applying these concepts to your following projects.\"))}MDXContent.isMDXComponent=!0;\n","scope":{}}}},"__N_SSG":true} |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"pageProps":{"tags":[{"name":"Deno","slug":"deno"},{"name":"Deno KV","slug":"deno-kv"},{"name":"TypeScript","slug":"typescript"},{"name":"JavaScript","slug":"javascript"},{"name":"Binary Arithmetic","slug":"binary-arithmetic"},{"name":"GitHub","slug":"github"},{"name":"GitHub Actions","slug":"github-actions"},{"name":"Coverage","slug":"coverage"},{"name":"3D","slug":"3d"},{"name":"Data Visualization","slug":"data-visualization"},{"name":"React Three Fiber","slug":"react-three-fiber"},{"name":"React","slug":"react"},{"name":"The Wandering Inn","slug":"the-wandering-inn"},{"name":"Three.js","slug":"threejs"},{"name":"Vercel","slug":"vercel"},{"name":"Art","slug":"art"},{"name":"Fanart","slug":"fanart"},{"name":"Vector","slug":"vector"},{"name":"Stable Diffusion","slug":"stable-diffusion"},{"name":"Inntober","slug":"inntober"},{"name":"Inktober","slug":"inktober"},{"name":"Linode","slug":"linode"},{"name":"Keybase","slug":"keybase"},{"name":"Hugo","slug":"hugo"},{"name":"Gitpod","slug":"gitpod"}]},"__N_SSG":true} |
File renamed without changes.
File renamed without changes.
Oops, something went wrong.