use 5.018; use warnings; use Math::BigInt; use Time::HiRes qw{ gettimeofday tv_interval }; use Fcntl; STDOUT->autoflush( 1 ); STDERR->autoflush( 1 ); my $startDigits; my $stopDigits; if ( scalar @ARGV == 2 ) { ( $startDigits, $stopDigits ) = @ARGV; } elsif ( scalar @ARGV == 1 ) { $startDigits = 2; $stopDigits = shift; } else { $startDigits = 2; $stopDigits = 8; } my $maxSteps = 0; my $nTried = 0; my $rcGenDigits; $rcGenDigits = sub { my( $depth, $start ) = @_; return [] unless $depth; my $raValues; foreach my $digit ( $start .. 9 ) { my $raInner = $rcGenDigits->( $depth - 1, $digit ); push @{ $raValues }, scalar @{ $raInner } ? map { $digit . $_ } @{ $raInner } : $digit; } return $raValues; }; my $steps; my $raRecord; my $startTV = my $lastTV = [ gettimeofday() ]; my $nowTV; my $elapsed; my $delta; foreach my $nDigits ( $startDigits .. $stopDigits ) { print q{ } x $stopDigits, qq{\rGenerating ${nDigits}-digit values ... }; my $raValues = $rcGenDigits->( $nDigits, 1 ); $nowTV = [ gettimeofday() ]; $delta = tv_interval( $lastTV, $nowTV ); $elapsed = tv_interval( $startTV, $nowTV ); $lastTV = $nowTV; say qq{found @{ [ scalar @{ $raValues } ] }, }, qq{took @{ [ scaleSecs( $delta ) ] }\n}, qq{Trying ${nDigits}-digit values, }, qq{at elapsed time @{ [ scaleSecs( $elapsed ) ] }\n}; foreach my $value ( @{ $raValues } ) { $nTried ++; print STDERR qq{$value\r} unless $nTried %1000; $raRecord = []; try( $value ); } $nowTV = [ gettimeofday() ]; $delta = tv_interval( $lastTV, $nowTV ); $lastTV = $nowTV; say q{ } x $stopDigits, qq{\nTrying ${nDigits}-digit values }, qq{took @{ [ scaleSecs( $delta ) ] }\n}; } say q{ } x $stopDigits, q{}; $nowTV = [ gettimeofday() ]; $elapsed = tv_interval( $startTV, $nowTV ); say qq{Total elapsed time @{ [ scaleSecs( $elapsed ) ] }\n}; sub per { my $nStr = shift; my $nVal = Math::BigInt->new( $nStr ); push @{ $raRecord }, [ $steps ++, $nVal->bstr() ]; return if $nVal->bcmp( 10 ) == -1; my $prod = Math::BigInt->new( 1 ); my %digits; $digits{ $_ } ++ for split m{}, $nVal->bstr(); $prod->bmul( $_ ) for map { $digits{ $_ } > 1 ? Math::BigInt->new( $_ )->bpow( $digits{ $_ } ) : $_ } keys %digits; return per( $prod->bstr() ); } sub scaleSecs { my $tv = shift; my $secs = int $tv; my( $fracPart ) = $tv =~ m{(?<=\.)(\d+)}; my $wks = 0; my $days = 0; my $hrs = 0; my $mins = 0; while($secs >= 604800) { $wks ++; $secs -= 604800; } while($secs >= 86400) { $days ++; $secs -= 86400; } while($secs >= 3600) { $hrs ++; $secs -= 3600; } while($secs >= 60) { $mins ++; $secs -= 60; } my $retStr = ( $wks ? qq{${wks}w } : q{} ) . ( $days ? qq{${days}d } : q{} ) . ( $hrs ? qq{${hrs}h } : q{} ) . ( $mins ? qq{${mins}m } : q{} ) . qq{$secs.${fracPart}s}; } sub try { my $nStr = shift; $steps = 0; per( $nStr ); my $actualSteps = $steps - 1; if ( $actualSteps > $maxSteps ) { $nowTV = [ gettimeofday() ]; $elapsed = tv_interval( $startTV, $nowTV ); say q{ } x $stopDigits, qq{\rFound steps: $actualSteps -- }, qq{at elapsed time @{ [ scaleSecs( $elapsed ) ] }}; printf qq{%7d %s\n}, @{ $_ } for @{ $raRecord }; $maxSteps = $actualSteps; } }