Hickerson series of almost integers
You are encouraged to solve this task according to the task description, using any language you may know.
The following function, due to D Hickerson is said to generate "Almost integers" by the "Almost Integer" page of Wolfram Mathworld. (December 31 2013).
The function is:
The function is said to produce "almost integers" for n in the given range.
Assume that an "almost integer" has either a nine or a zero as its first digit after the decimal point of its decimal string representation
The task is to calculate all values of the function checking and stating which are "almost integers".
Note: Use extended/arbitrary precision numbers in your calculation if necessary to ensure you have adequate precision of results as for example:
h(18) = 3385534663256845326.39...
C++
<lang cpp>#include <iostream>
- include <iomanip>
- include <boost/multiprecision/cpp_dec_float.hpp>
- include <boost/math/constants/constants.hpp>
typedef boost::multiprecision::cpp_dec_float_50 decfloat;
int main() {
const decfloat ln_two = boost::math::constants::ln_two<decfloat>(); decfloat numerator = 1, denominator = ln_two; for(int n = 1; n <= 17; n++) { decfloat h = (numerator *= n) / (denominator *= ln_two) / 2; decfloat tenths_dig = floor((h - floor(h)) * 10); std::cout << "h(" << std::setw(2) << n << ") = " << std::setw(25) << std::fixed << h << (tenths_dig == 0 || tenths_dig == 9 ? " is " : " is NOT ") << "an almost-integer.\n"; }
} </lang>
- Output:
h( 1) = 1.040684 is an almost-integer. h( 2) = 3.002781 is an almost-integer. h( 3) = 12.996291 is an almost-integer. h( 4) = 74.998735 is an almost-integer. h( 5) = 541.001519 is an almost-integer. h( 6) = 4683.001247 is an almost-integer. h( 7) = 47292.998731 is an almost-integer. h( 8) = 545834.997907 is an almost-integer. h( 9) = 7087261.001623 is an almost-integer. h(10) = 102247563.005271 is an almost-integer. h(11) = 1622632572.997550 is an almost-integer. h(12) = 28091567594.981572 is an almost-integer. h(13) = 526858348381.001248 is an almost-integer. h(14) = 10641342970443.084532 is an almost-integer. h(15) = 230283190977853.037436 is an almost-integer. h(16) = 5315654681981354.513077 is NOT an almost-integer. h(17) = 130370767029135900.457985 is NOT an almost-integer.
Clojure
This first implementation uses regular precision, which is not enough for this purpose.
<lang clojure>(defn hickerson
"Hickerson number, calculated with default floating-point settings." [n] (let [n! (apply * (range 1 (inc n)))] (/ n! (* 2 (Math/pow (Math/log 2) (inc n))))))
(defn almost-integer?
"Tests whether the first digit in the decimal expansion of a number is 0 or 9." [x] (let [first-digit (int (Math/floor (* 10 (- x (Math/floor x)))))] (or (= 0 first-digit) (= 9 first-digit))))
- Execute for side effects
(doseq [n (range 1 18)
:let [h (hickerson n)]] (println (format "%2d %24.5f" n h) (if (almost-integer? h) "almost integer" "NOT almost integer")))</lang>
- Output:
1 1,04068 almost integer 2 3,00278 almost integer 3 12,99629 almost integer 4 74,99874 almost integer 5 541,00152 almost integer 6 4683,00125 almost integer 7 47292,99873 almost integer 8 545834,99791 almost integer 9 7087261,00162 almost integer 10 102247563,00527 almost integer 11 1622632572,99755 almost integer 12 28091567594,98158 almost integer 13 526858348381,00150 almost integer 14 10641342970443,09000 almost integer 15 230283190977853,16000 NOT almost integer 16 5315654681981358,00000 almost integer 17 130370767029135968,00000 almost integer nil
COBOL
<lang cobol> >>SOURCE FREE IDENTIFICATION DIVISION. PROGRAM-ID. hickerson-series.
ENVIRONMENT DIVISION. CONFIGURATION SECTION. REPOSITORY.
FUNCTION ALL INTRINSIC .
DATA DIVISION. WORKING-STORAGE SECTION. 01 n PIC 99 COMP.
01 h PIC Z(19)9.9(10).
01 First-Decimal-Digit-Pos CONSTANT 22.
PROCEDURE DIVISION.
PERFORM VARYING n FROM 0 BY 1 UNTIL n > 17 COMPUTE h = FACTORIAL(n) / (2 * LOG(2) ** (n + 1)) DISPLAY "h(" n ") = " h " which is " NO ADVANCING IF h (First-Decimal-Digit-Pos:1) = "0" OR "9" DISPLAY "an almost integer." ELSE DISPLAY "not an almost integer." END-IF END-PERFORM .
END PROGRAM hickerson-series.</lang>
- Output:
h(00) = 0.7213475204 which is not an almost integer. h(01) = 1.0406844905 which is an almost integer. h(02) = 3.0027807071 which is an almost integer. h(03) = 12.9962905052 which is an almost integer. h(04) = 74.9987354476 which is an almost integer. h(05) = 541.0015185164 which is an almost integer. h(06) = 4683.0012472622 which is an almost integer. h(07) = 47292.9987313146 which is an almost integer. h(08) = 545834.9979074851 which is an almost integer. h(09) = 7087261.0016228991 which is an almost integer. h(10) = 102247563.0052710420 which is an almost integer. h(11) = 1622632572.9975500498 which is an almost integer. h(12) = 28091567594.9815724407 which is an almost integer. h(13) = 526858348381.0012482861 which is an almost integer. h(14) = 10641342970443.0845319270 which is an almost integer. h(15) = 230283190977853.0374360391 which is an almost integer. h(16) = 5315654681981354.5130767434 which is not an almost integer. h(17) = 130370767029135900.4579853491 which is not an almost integer.
D
The D real
type has enough precision for this task.
<lang d>import std.stdio, std.algorithm, std.mathspecial;
void main() {
foreach (immutable n; 0 .. 18) { immutable x = gamma(n + 1) / (2 * LN2 ^^ (n + 1)), tenths = cast(int)floor((x - x.floor) * 10); writefln("H(%2d)=%22.2f is %snearly integer.", n, x, [0, 9].canFind(tenths) ? "" : "NOT "); }
}</lang>
H( 0)= 0.72 is NOT nearly integer. H( 1)= 1.04 is nearly integer. H( 2)= 3.00 is nearly integer. H( 3)= 13.00 is nearly integer. H( 4)= 75.00 is nearly integer. H( 5)= 541.00 is nearly integer. H( 6)= 4683.00 is nearly integer. H( 7)= 47293.00 is nearly integer. H( 8)= 545835.00 is nearly integer. H( 9)= 7087261.00 is nearly integer. H(10)= 102247563.01 is nearly integer. H(11)= 1622632573.00 is nearly integer. H(12)= 28091567594.98 is nearly integer. H(13)= 526858348381.00 is nearly integer. H(14)= 10641342970443.08 is nearly integer. H(15)= 230283190977853.04 is nearly integer. H(16)= 5315654681981354.51 is NOT nearly integer. H(17)= 130370767029135900.50 is NOT nearly integer.
Go
<lang go>package main
import (
"fmt" "math/big"
)
func main() {
ln2, _ := new(big.Rat).SetString("0.6931471805599453094172") h := big.NewRat(1, 2) h.Quo(h, ln2) var f big.Rat var w big.Int for i := int64(1); i <= 17; i++ { h.Quo(h.Mul(h, f.SetInt64(i)), ln2) w.Quo(h.Num(), h.Denom()) f.Sub(h, f.SetInt(&w)) y, _ := f.Float64() d := fmt.Sprintf("%.3f", y) fmt.Printf("n: %2d h: %18d%s Nearly integer: %t\n", i, &w, d[1:], d[2] == '0' || d[2] == '9') }
}</lang>
- Output:
n: 1 h: 1.041 Nearly integer: true n: 2 h: 3.003 Nearly integer: true n: 3 h: 12.996 Nearly integer: true n: 4 h: 74.999 Nearly integer: true n: 5 h: 541.002 Nearly integer: true n: 6 h: 4683.001 Nearly integer: true n: 7 h: 47292.999 Nearly integer: true n: 8 h: 545834.998 Nearly integer: true n: 9 h: 7087261.002 Nearly integer: true n: 10 h: 102247563.005 Nearly integer: true n: 11 h: 1622632572.998 Nearly integer: true n: 12 h: 28091567594.982 Nearly integer: true n: 13 h: 526858348381.001 Nearly integer: true n: 14 h: 10641342970443.085 Nearly integer: true n: 15 h: 230283190977853.037 Nearly integer: true n: 16 h: 5315654681981354.513 Nearly integer: false n: 17 h: 130370767029135900.458 Nearly integer: false
Perl 6
We'll use FatRat values, and a series for an approximation of ln(2).
<lang perl6>constant ln2 = [\+] map { 1.FatRat / 2**$_ / $_ }, 1 .. *; constant fact = 1, [\*] 1..*;
sub h(Int $n --> FatRat) { fact[$n] / (2 * ln2[100]**($n+1)) }
use Test; plan 17;
for 1 .. 17 -> $n {
ok m/'.'<[09]>/, .round(0.001) given h($n);
}</lang>
- Output:
1..17 ok 1 - 1.041 ok 2 - 3.003 ok 3 - 12.996 ok 4 - 74.999 ok 5 - 541.002 ok 6 - 4683.001 ok 7 - 47292.999 ok 8 - 545834.998 ok 9 - 7087261.002 ok 10 - 102247563.005 ok 11 - 1622632572.998 ok 12 - 28091567594.982 ok 13 - 526858348381.001 ok 14 - 10641342970443.085 ok 15 - 230283190977853.037 not ok 16 - 5315654681981354.513 not ok 17 - 130370767029135900.458 # Looks like you failed 2 tests of 17
Python
This uses Pythons decimal module of fixed precision decimal floating point calculations.
<lang python>from decimal import Decimal import math
def h(n):
'Simple, reduced precision calculation' return math.factorial(n) / (2 * math.log(2) ** (n + 1))
def h2(n):
'Extended precision Hickerson function' return Decimal(math.factorial(n)) / (2 * Decimal(2).ln() ** (n + 1))
for n in range(18):
x = h2(n) norm = str(x.normalize()) almostinteger = (' Nearly integer' if 'E' not in norm and ('.0' in norm or '.9' in norm) else ' NOT nearly integer!') print('n:%2i h:%s%s' % (n, norm, almostinteger))</lang>
- Output:
n: 0 h:0.7213475204444817036799623405 NOT nearly integer! n: 1 h:1.040684490502803898934790802 Nearly integer n: 2 h:3.002780707156905443499767406 Nearly integer n: 3 h:12.99629050527696646222488454 Nearly integer n: 4 h:74.99873544766160012763455035 Nearly integer n: 5 h:541.0015185164235075692027746 Nearly integer n: 6 h:4683.001247262257437180467151 Nearly integer n: 7 h:47292.99873131462390482283547 Nearly integer n: 8 h:545834.9979074851670672910395 Nearly integer n: 9 h:7087261.001622899120979187513 Nearly integer n:10 h:102247563.0052710420110883885 Nearly integer n:11 h:1622632572.997550049852874859 Nearly integer n:12 h:28091567594.98157244071518915 Nearly integer n:13 h:526858348381.0012482861804887 Nearly integer n:14 h:10641342970443.08453192709506 Nearly integer n:15 h:230283190977853.0374360391257 Nearly integer n:16 h:5315654681981354.513076743451 NOT nearly integer! n:17 h:130370767029135900.4579853491 NOT nearly integer!
The range for should be reduced to be for this definition of almost integer.
REXX
<lang rexx>/* REXX ---------------------------------------------------------------
- 04.01.2014 Walter Pachl - using a rather aged ln function of mine
- with probably unreasonably high precision
- --------------------------------------------------------------------*/
Numeric Digits 100 Do n=1 To 17
x=format(def(),20,10) Parse Var x '.' +1 d +1 If pos(d,'09')>0 Then tag='almost an integer' Else tag= Say right(n,2) x tag End
Exit
def:
x=fact(n)/(2*ln(2,200)**(n + 1)) Return x
ln: Procedure /***********************************************************************
- Return ln(x) -- with specified precision
- Three different series are used for the ranges 0 to 0.5
- 0.5 to 1.5
- 1.5 to infinity
- 920903 Walter Pachl
- /
Parse Arg x,prec,b If prec= Then prec=9 Numeric Digits (2*prec) Numeric Fuzz 3 Select When x<=0 Then r='*** invalid argument ***' When x<0.5 Then Do z=(x-1)/(x+1) o=z r=z k=1 Do i=3 By 2 ra=r k=k+1 o=o*z*z r=r+o/i If r=ra Then Leave End r=2*r End When x<1.5 Then Do z=(x-1) o=z r=z k=1 Do i=2 By 1 ra=r k=k+1 o=-o*z r=r+o/i If r=ra Then Leave End End Otherwise /* 1.5<=x */ Do z=(x+1)/(x-1) o=1/z r=o k=1 Do i=3 By 2 ra=r k=k+1 o=o/(z*z) r=r+o/i If r=ra Then Leave End r=2*r End End If b<> Then r=r/ln(b) Numeric Digits (prec) Return r+0
fact: Procedure
Parse Arg m fact=1 Do i=2 To m fact=fact*i End Return fact</lang>
- Output:
1 1.0406844905 almost an integer 2 3.0027807072 almost an integer 3 12.9962905053 almost an integer 4 74.9987354477 almost an integer 5 541.0015185164 almost an integer 6 4683.0012472623 almost an integer 7 47292.9987313146 almost an integer 8 545834.9979074852 almost an integer 9 7087261.0016228991 almost an integer 10 102247563.0052710420 almost an integer 11 1622632572.9975500499 almost an integer 12 28091567594.9815724407 almost an integer 13 526858348381.0012482862 almost an integer 14 10641342970443.0845319271 almost an integer 15 230283190977853.0374360391 almost an integer 16 5315654681981354.5130767435 17 130370767029135900.4579853492
Ruby
Using the BigDecimal standard library: <lang ruby> require "bigdecimal"
LN2 = BigMath::log(2,16) #Use LN2 = Math::log(2) to see the difference with floats FACTORIALS = Hash.new{|h,k,v| h[k]=k * h[k-1]} FACTORIALS[0] = 1
def hickerson(n)
FACTORIALS[n] / (2 * LN2 ** (n+1))
end
def nearly_int?(n)
int = n.round n.between?(int - 0.1, int + 0.1)
end
1.upto(17) do |n|
h = hickerson(n) str = nearly_int?(h) ? "nearly integer" : "NOT nearly integer" puts "n:%3i h: %s\t%s" % [n, h.to_s('F')[0,25], str] #increase the 25 to print more digits, there are 856 of them
end
</lang>
- Output:
n: 1 h: 1.04068449050280389893479 nearly integer n: 2 h: 3.00278070715690544349976 nearly integer n: 3 h: 12.9962905052769664622248 nearly integer n: 4 h: 74.9987354476616001276345 nearly integer n: 5 h: 541.001518516423507569202 nearly integer n: 6 h: 4683.00124726225743718046 nearly integer n: 7 h: 47292.9987313146239048228 nearly integer n: 8 h: 545834.997907485167067291 nearly integer n: 9 h: 7087261.00162289912097918 nearly integer n: 10 h: 102247563.005271042011088 nearly integer n: 11 h: 1622632572.99755004985287 nearly integer n: 12 h: 28091567594.9815724407151 nearly integer n: 13 h: 526858348381.001248286180 nearly integer n: 14 h: 10641342970443.0845319270 nearly integer n: 15 h: 230283190977853.037436039 nearly integer n: 16 h: 5315654681981354.51307674 NOT nearly integer n: 17 h: 130370767029135900.457985 NOT nearly integer