Home > database >  How to define a 128-bit variable, or larger, in Powershell?
How to define a 128-bit variable, or larger, in Powershell?

Time:11-25

I need a single variable which can store a 128-bit, unsigned integer. The largest type that Powershell recognizes, however, is UInt64. Is it possible to define a UInt128, or even UInt256 variable?

For context, I'm using Powershell 7.2.0.

CodePudding user response:

From your comments:

I want to find prime numbers within the Fibonacci sequence, which is why I need such a large integer size

For this, [bigint] (type accelerator for the System.Numerics.BigInteger type) is what you want - it doesn't have any upper boundary and is designed specifically for doing integer aritmetic with large values - exactly the kind of thing you need when hunting for primes!

[...] most Powershell functions, especially those in [Math], aren't made for BigInteger.

The good news is the [bigint] brings its own!

Here's how you could implement a simple (and slow) recursive Fibonacci generator with [bigint]:

function Get-FibonacciTerm {
  param(
    [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
    [int]$N
  )

  process {
    if($N -lt 1){ return [bigint]::Zero }
    if($N -lt 3){ return [bigint]::One }

    return (Get-FibonacciTerm -N ($N-1))   (Get-FibonacciTerm -N ($N-2))
  }
}
PS ~> 1..12 |Get-FibonacciTerm
1
1
2
3
5
8
13
21
34
55
89
144

As you might have noticed, basic arithmetic operators like is overloaded by [bigint] and therefore works exactly as you'd expect "out of the box".

In addition, [bigint] provides a set of static helper methods to provide cognates to most of the static [math] functions. Here's a simple (and again, fairly slow/inefficient) Prime generator/tester using some of them:

function Get-PrimeNumber {
  param(
    [bigint]$Below = 1000
  )

  for($i = [bigint]::Zero; $i -lt $Below; $i = [bigint]::Add($i, [bigint]::One)){
    if($i -le 1){ continue }
    if([bigint]::Remainder($i, 2) -eq 0){ 
      if($i -eq 2){ $i }
      continue
    }
    
    $foundFactor = $false

    for($j = 3; $j -lt $i; $j = [bigint]::Add($j, 2)){
      if([bigint]::Remainder($i, $j) -eq 0){
        $foundFactor = $true
        break
      }
    }

    if(-not $foundFactor){ $i }
  }
}
PS ~> Get-PrimeNumber -Below 100
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97

Now, the first optimization you might want to make here is to only search up until the root of $i in the inner loop. This is where [bigint] starts to diverge from [math] - there's no built-in Sqrt() function!

Luckily, you can roll your own :)

In conclusion:

  • For large integer arithmetic, [bigint] is definitely your friend
  • It doesn't quite have complete feature parity with builtin integral types, but supports basic arithmetic operations

I see now that a scripting language may not be the best bet for a use case such as this

I wouldn't be so quick to dismiss the entire category of "scripting languages" - PowerShell is not necessarily a good fit for this use case, because optimization of large integer math has never been a major priority in neither PowerShell nor .NET - but there are other languages out there better suited because they've been optimized for it.

Python (>=3.x) natively supports unbounded numbers and is generally much faster for arithmetic operations than PowerShell. JavaScript also has support for a BigInt type similar to [bigint] for numbers >2^53, also surprisingly fast.

  • Related