Sunday, November 29, 2020

HP Prime: Linear Exponential Combination Fit

 HP Prime:  Linear Exponential Combination Fit


The program LINEXPREG attempts to fit bivariate data to the curve:


y = a + b * x + c * e^x


The LSQ (least square) function is used.  The output is a list of three matrices:



*  A matrix of coefficients:  [ [ a ] [ b ] [ c ] ] 


*  A matrix of y values entered


*  A matrix of predicted y values



HP Prime Program LINEXPREG


EXPORT LINEXPREG(lx,ly)

BEGIN

// 2020-11-17 EWS

// x list, y list

LOCAL n,lx2,lx3,mx,my,k,mr,mq;

n:=SIZE(lx);

lx2:=e^(lx);

lx3:={};

FOR k FROM 1 TO n DO

lx3:=CONCAT(lx3,{1,lx(k),lx2(k)});

END;

mx:=list2mat(lx3,3);

my:=list2mat(ly,1);

mq:=LSQ(mx,my);

mr:=mq(1,1)+mq(2,1)*lx+

mq(3,1)*e^(lx);

mr:=list2mat(mr,1);

RETURN {mq,my,mr};

END;


Example





x list:  {0, 1, 2, 3, 4, 5}

y list:  {2, 7, 13, 18, 26, 34}


LINEXPREG({0, 1, 2, 3, 4, 5},{2, 7, 13, 18, 26, 34})


Results:  {coefficients, y values, predicted y values}


coefficients:

[ [ 1.74935499143 ]

[ 5.39455446221 ]

[ 3.66584105034E-2 ] ] 


y values:

[ [ 2 ]

[ 7 ]

[ 13 ]

[ 18 ]

[ 26 ]

[ 34 ] ]


predicted y values:

[ [  1.78601340193 ]

[ 7.24355734477 ]

[ 12.8093349675 ]

[ 18.6693222357 ]

[ 25.3290542368 ]

[ 34.1627178129 ] ] 


Equation:

y = 1.74935499143 + 5.39455446221 * x + 3.66584105034E-2 * e^x


On to the last month of 2020...


Eddie


All original content copyright, © 2011-2020.  Edward Shore.   Unauthorized use and/or unauthorized distribution for commercial purposes without express and written permission from the author is strictly prohibited.  This blog entry may be distributed for noncommercial purposes, provided that full credit is given to the author. 


Saturday, November 28, 2020

Review: Ativa 2-Line Calculator DD-2361

 Review:  Ativa 2-Line Calculator DD-2361


Just the Facts:


Model:  DD-2361 (I was stated in the manual)

Company: Ativa (Office Depot)

Type: Four Function

Battery:  Solar with backup battery LR1130

Logic: Algebraic

Memory Registers: None

Price:  $8.99





A Two Line Screen

The Ativa DD-2361 calculator has a two lines: the top line shows the entered expression.  Each calculation can have up to 79 characters.   The bottom line shows answers, which can have up to 12 characters.  

Functions include the percent function which, works like four function calculators.  

Example:  

Top:  7 x 8 - 2 x 9

Bottom:  38


The order of operations are used.  


The keys on the keyboard are huge and responsive.  Expressions can be edited using left and right arrow keys.  Characters are replaced in editing.  


Verdict


I like the big keys.  The DD-2361 does lack a few key features: square root, an independent memory register, and due to the calculator following the order of operations, parenthesis.  This is one of few two-line four-function calculators where you can buy it a store, and not just online.  


Eddie


All original content copyright, © 2011-2020.  Edward Shore.   Unauthorized use and/or unauthorized distribution for commercial purposes without express and written permission from the author is strictly prohibited.  This blog entry may be distributed for noncommercial purposes, provided that full credit is given to the author. 


Sunday, November 22, 2020

Heron's Formula vs Area by Vertices

Heron's Formula vs Area by Vertices

There are several ways to determine the area of a triangle.

Heron's Formula:

With side lengths A, B, and C, the area is:

Area = √( S * (S - A) * (S - B) * (S - C) ) 

where S = (A + B + C) / 2

Area of Vertices:

With vertices (x1, y1), (x2, y2), and (x3, y3), the area is:

Area = 1/2 * abs( (x1 - x2) * (y1 + y2) + (x2 - x3) * (y2 + y3) + (x3 - x1) * (y3 + y1) )

Testing The Data






I ran a test of 50 randomly selected sets of three points that form the triangle.  The three points are:
*  The origin: (0,0)
*  The second point has 0 ≤ x ≤ 20 and -20 ≤ y ≤ 20, x and y are integers
*  The third point has 0 ≤ x ≤ 20 and 0 ≤ y ≤ 20, x and y are integers

I used the Casio fx-9750gIII Spreadsheet application.    

Casio Spreadsheet Set Up

Column Titles - Row 1:

Column A:  "X1"   x coordinate of point 1
Column B:  "Y1"   y coordinate of point 1
Column C:  "X2"   x coordinate of point 2. 
Column D:  "Y2"  y coordinate of point 2
Column E:  "X3"  x coordinate of point 3
Column F:  "Y3"  y coordinate of point 3
Column G:  "XY1"  distance between points 1 and 2
Column H:  "XY2"  distance between points 2 and 3
Column I:  "XY3"  distance between 3 and 1
Column J:  "S"   semi-perimeter of the triangle
Column K:  "HERON"  Area by Heron's Formula
Column L: "VERT"  Area by Vertices 
Column M:  "DIFF"  Difference between two calculation methods

Formulas for Rows 2 through 51

Column A:  A2 = Fill(0,50)
Column B:  B2 =Fill(0,50)
Column C:  C2 =Seq(Int(22 Ran#) - 1,X,1,50,1)
Column D:  D2 =Seq(Int(41 Ran#) - 21,X,1,50,1)
Column E:  E2 =Seq(Int(22 Ran#) - 1,X,1,50,1)
Column F:  F2 =Seq(Int(22 Ran#)-1, X,1,50,1)
Column G:  G2 Fill:  =√(C2^2 + D2^2) for range G2:G51*
Column H:  H2 Fill:  =√((C2-E2)^2 + (D2-F2)^2) for range H2:H51
Column I:  I2 Fill:  =√(E2^2 + F2^2) for range I2:I51*
Column J: J2  Fill:  =(G2 + H2 + I2) ÷ 2 for range J2:J51
Column K:  K2 Fill =√(J2 (J2 - G2) (J2 - H2) (J2 - I2) ) for range K2:K51
Column L:  L2 Fill =0.5 × Abs( (A2 - C2)(B2 + D2) + (C2 - E2)(D2 + F2) 
+ (E2 - A2)(F2 + B2)) for range L2: L51
Column M:  M2  Fill =K2-L2

 * To take advantage that the first point is (0, 0).  The full distance formula would be needed otherwise.  

This spreadsheet implies that there is no "rounding" the middle results.  


If you want to download the spreadsheet results, click here:


The zip file contains two images, a csv file, and a Casio spreadsheet file that can be ran on Casio calculators with a spreadsheet application. 

Of the sample taken, the areas determined by Heron's Formula and Area by Vertices are substantially equal; any difference is the order of 10^-12.

Happy Thanksgiving,

Eddie

All original content copyright, © 2011-2020.  Edward Shore.   Unauthorized use and/or unauthorized distribution for commercial purposes without express and written permission from the author is strictly prohibited.  This blog entry may be distributed for noncommercial purposes, provided that full credit is given to the author. 

Saturday, November 21, 2020

Numworks: 3 x 3 Matrices

 Numworks:   3 x 3 Matrices


The script invthree.py calculates the inverse and determinant of a 3 x 3 matrix.  


Matrices:


[[ a1,  a2,  a3 ]

[ b1, b2, b3 ]

[ c1, c2, c3 ]]



Numworks script invthree.py:

(701 bytes)


from math import *


# 2020-11-12 EWS

print("3x3 Matrix Inverse")

print("[[a1,a2,a3]")

print("[b1,b2,b3]")

print("[c1,c2,c3]]")

a1=float(input('a1: '))

a2=float(input('a2: '))

a3=float(input('a3: '))

b1=float(input('b1: '))

b2=float(input('b2: '))

b3=float(input('b3: '))

c1=float(input('c1: '))

c2=float(input('c2: '))

c3=float(input('c3: '))

# determinant

d=a1*(b2*c3-b3*c2)-a2*(b1*c3-b3*c1)+a3*(b1*c2-b2*c1)

# inverse

d1=(b2*c3-c2*b3)/d

d2=-(a2*c3-c2*a3)/d

d3=(a2*b3-a3*b2)/d

e1=-(b1*c3-c1*b3)/d

e2=(a1*c3-c1*a3)/d

e3=-(a1*b3-a3*b1)/d

f1=(b1*c2-b2*c1)/d

f2=-(a1*c2-a2*c1)/d

f3=(a1*b2-a2*b1)/d

print("det=")

print(d)

print("inv=")

print([d1,d2,d3])

print([e1,e2,e3])

print([f1,f2,f3])


Numworks page:  https://workshop.numworks.com/python/ews31415/invthree


Example:


[[ -5.4, 3.3, -1.7 ], [ 0.6, 8.3, 5.3 ] [ 5.5, 5.4, 1.9 ]] 


returns 


[ -0.05493...,  -0.06604..., 0.13508... ]

[ 0.11974... ,  -0.00389..., 0.11798... ]

[ -0.18130..., 0.20224..., -0.20006... ]


Source:


wikiHow Staff "How to Find the Inverse of a 3x3 Matrix"  WikiHow.   Last Updated November 5, 2020.  https://www.wikihow.com/Find-the-Inverse-of-a-3x3-Matrix  Retrieved November 12, 2020.


Eddie


All original content copyright, © 2011-2020.  Edward Shore.   Unauthorized use and/or unauthorized distribution for commercial purposes without express and written permission from the author is strictly prohibited.  This blog entry may be distributed for noncommercial purposes, provided that full credit is given to the author. 


Sunday, November 15, 2020

HP 41C and DM41: Operations by Test, Messages, Block Storage

 HP 41C and DM41: Operations by Test, Messages, Block Storage  


The programs are inspired from a great calculator resource, "Calculator Tips & Routines Especially For The HP-41C/41CV", edited by John Dearing (see source below).   


Operations by Test


One of the tips presented is the selection of one of two opposite arithmetic operations based on a comparison between X and Y values.  This tip was provided by Bill Kolb (tip 2-7).  They are:


X?Y

CHS  (subtract if test is true)

+   (add if test is false)


X?Y

1/X  (divide if the test is true)

*  (multiply if the test is false)


X?Y

1/X   (take the root if the test is true)

Y↑X  (take the power if the test is false)


The following programs uses the test X<Y:


TESTAS:  X<Y  (subtract, y - x),  X≥Y (adding, y + x)


(^T represent the beginning of an alpha string)


01 LBL^T TESTAS

02 X<Y?

03 CHS

04 + 

05 END


Example:  

45, 13, XEQ TESTAS returns 32  (45 - 13)

13, 45, XEQ TESTAS returns 58  (13 + 45)


TESTMD:  X<Y  (divide, y/x),  X≥Y (mulitply, y * x)


01 LBL^T TESTMD

02 X<Y?

03 1/X

04 * 

05 END


Example:  

45, 13, XEQ TESTMD returns 3.4615  ( ≈ 45 / 13)

13, 45, XEQ TESTMD returns 585  (13 * 45)


TESTPR:  X<Y  (root, y^1/x),  X≥Y (power, y^x)


01 LBL^T TESTPR

02 X<Y?

03 1/X

04 Y↑X 

05 END


Example:  

49, 3, XEQ TESTPR returns 3.6593  ( ≈ 49 ^ 1/3)

3, 49, XEQ TESTPR returns 2.3930E23  (≈ 3 ^ 49)


Messages


With the use of AVIEW during a loop, you can display a loop up to 12 characters while the loop is running.   A CLD (clear display) is added after the loop's completion to clear the alpha display and show the stack. (tip 2-25)


The program TESTSUM adds a message while the 41C is summing numbers from 1 to X.   While this is not the most efficient way to tackle the problem, this illustrates the use of messages.  


01 LBL^T TESTSUM

02 STO 01

03 0

04 STO 02

05 LBL 01   // loop begins

06 RCL 01

07 ST+ 02

08 ^T ADDING...  // message

09 AVIEW   // display the message

10 DSE 01

11 GTO 01

12 CLD  // clear display

13 RCL 02

14 END


Example:

50, XEQ TESTSUM  

Display: ADDING..., then 1275


Block Storage


You can use indirect storage and the stack to store a constant in a block of consecutive storage registers.  A sample loop:


LBL %%

STO IND Y

ISG Y

GTO %%


Where %% is a label, and the loop variable is B.EEE  (B:  beginning register, E:  ending register) stored in this case, Stack Y.  (tip 10-1)


The program LOADBLK, prompts the user enter the value, beginning register number, and ending register number.


01 LBL^LOADBLK

02 ^T VALUE

03 PROMPT

04 STO Z     // keystrokes:  [ STO ]  [ . ]  ( Y )

05 ^T R%% BGN?

06 PROMPT

07 ^T R%% END?

08 PROMPT

09 1E3

10 /

11 +

12 STO Y  

13 RDN   // R↓

14 X<>Y

15 LBL 01

16 STO IND Y   // keystrokes:  [ STO ] [ shift ] [ . ] ( Y )

17 ^T STORING...    // message

18 AVIEW

19 ISG Y    // keystrokes:  [ shift ] ( ISG ) [ . ] ( Y )

20 GTO 01

21 ^T DONE

22 AVIEW

23 PSE

24 CLD

25 END


Try this:

Store π in R00 to R03 and e^1 in R04 to R07.

 

Results:  (Fix 4)

R00:  3.1416

R01:  3.1416

R02:  3.1416

R03:  3.1416

R04:  2.7183

R05:  2.7183

R06:  2.7183

R07:  2.7183


Source:


Dearing, John.  "Calculator Tips & Routines Especially for the HP-41C/41CV"  Corvallis Software, Inc.   Corvallis, OR.  1981 


Link on HP41.org (account needed):  http://www.hp41.org/LibView.cfm?Command=View&ItemID=320



Eddie


All original content copyright, © 2011-2020.  Edward Shore.   Unauthorized use and/or unauthorized distribution for commercial purposes without express and written permission from the author is strictly prohibited.  This blog entry may be distributed for noncommercial purposes, provided that full credit is given to the author. 


Saturday, November 14, 2020

HP Prime: The Percent Function

 HP Prime:  The Percent Function


The Percent Function



The HP Prime has three percent functions.   They are not easily found (through the catalog or in program edit mode, Cmds-More menu).  The functions are:


%

%CHANGE

%TOTAL


% Function


%(x, y)  returns x * y /100.  This returns either x% of y or y% of x.  Due to the communicative multiplication property, you can use the arguments in either order.  


%CHANGE


This the percent change function where the arguments are %CHANGE(old, new).  Formula:  %CHANGE(x, y) = (y - x) / x * 100%


%TOTAL


This calculates the % total given a part and a whole.  Syntax:  %TOTAL(whole, part).  Formula:  %TOTAL(x, y) = y / x * 100%


The program POPTOWN uses the percent functions.  It is a simple game where you invite a certain population to live in a town, and the birth (growth) and death rates are determined by random.


HP Prime Prime Program:  POPTOWN


RESULTS(y,n,g,d,p)

BEGIN

// subroutine

PRINT();

PRINT("Year: "+STRING(y));

PRINT("Population: "+STRING(n));

IF y>0 THEN

PRINT("Growth: "+STRING(g)+"%");

PRINT("Death: "+STRING(d)+"%");

PRINT("Δ%: "+%CHANGE(p,n));

END;

WAIT(0);

END;


// main program

EXPORT POPTOWN()

BEGIN

MSGBOX("You start with 10 

residents, inviting up to 50 

new residents each year.  Can 

growth beat death?");

// 2020-10-24 EWS

// Growth and Death

LOCAL n,y,w,g,d,c,p;

LOCAL v; // number of invites

n:=10;

RESULTS(y,n,g,d,p);

// The game

FOR y FROM 1 TO 5 DO

INPUT({{c,{0,10,20,30,40,50}}},

"Year "+STRING(y),"Invite:");

// all invites move in at the

// beginning of each turn

p:=n;

w:=10*(c-1)+n;

v:=10*(c-1)+v;

g:=RANDINT(5,20);

d:=RANDINT(1,25);

n:=w+IP(%(w,g))-IP(%(w,d));

// empty town scenario

IF n≤0 THEN

MSGBOX("No one survived.");

n:=0; 

END;

RESULTS(y,n,g,d,p);

END;

// End the game results

PRINT("Final Results");

PRINT("Population Change: "+

STRING(n-10));

PRINT("Invited: "+STRING(v));

PRINT("Percent Invite: "+

STRING(ROUND(%TOTAL(n,v),2))

+"%");

END;



Eddie


All original content copyright, © 2011-2020.  Edward Shore.   Unauthorized use and/or unauthorized distribution for commercial purposes without express and written permission from the author is strictly prohibited.  This blog entry may be distributed for noncommercial purposes, provided that full credit is given to the author. 


Saturday, November 7, 2020

HP Prime: Approximate of a Quartic Root

 HP Prime: Approximate of a Quartic Root


Introduction


In the article "Square Root & Cube Root Algorithms" (see source below), teacher and educator Dave  Elgin wrote an article on how his Advanced Higher Applied Mathematics class developed algorithms to estimate the square root and cubic roots of numbers.  The algorithms are first based off of Netwon's Method, then uses selected initial guesses and solving for linear systems.


Elgin's Derivation 


Square Root


Suppose x^2 = k.   To set up for Newton's Method, let f(x) = x^2 - k, with df/dx = 2x.  Then


x_n+1 = x_n - (x_n^2 - k) / (2 * x_n) = 1/2 * (x_n + k / x_n^2)


(The article uses N for the number to find the root of, but to eliminate confusion, I use k.  Completely a choice of labels.)


The class used a pattern to determine guesses for the square root of k:


k / (x_n),  (k^2) / (x_n^3),  (k^3) / (x_n^5), and so on.   


Let g(x) be an iterative function where x_n+1 = g(x_n) and for a second-order approximation:


g(x) = a1 * x + a2 * k / x + a3 * k^2 / x^3


Two derivatives of g(x) are taken:


g'(x) = a1 - a2 * k / x^2 - 3 * a3 * k^2 / x^4, with g'(x_n) = 0


g''(x) = 2 * a2 * k / x^3 + 12 * a3 * k^2 / x^5 with g''(x_n) = 0


This requires the following system of equations to be solved for a1, a2, and a3 (after substituting x = √k):


1 = a1 + a2 + a3

0 = a1 - a2 - 3 * a3

0 = 2 * a2 + 12 * a3


leading to the solutions a1 = 3/8, a2 = 3/4, and a3 = -1/8


Hence the second-order recursive function for the square root is (after simplifying):


g(x) = 3/8 * x + (3 * k) / (4 * x) -  k^2 / (8 * x^3)


which translates to 


x_n+1 = 3/8 * x_n + (3 * k) / (4 * x_n) -  k^2 / (8 * x_n^3)


Cube Root


They repeat the same process for the cubic root, which I will briefly outline here:


x^3 = k,   f(x) = x^3 - k,  f'(x) = 3x^2


x_n+1 = x_n - (x^3 - k) / (3x^2) = 1/3 * (2 * x_n - k / (x_n^2))


With guess of k / (x_n^2) and k^2 / (x_n^5) used, the iterative function is set up as:


g(x) = a1 * x + a2 * k / x^2 + a3 * k^2 / x^5


and


g'(x) = a1 - 2 * a2 * k / x^3 - 5 * a3 * k^2 / x^6


g''(x) = 6 * a2 * k / x^4 + 30 * a3 * k^2 / x^7


and with g(x_n) = x_n+1, g'(x_n) = 0, g''(x_n) = 0 and substituting x = k^1/3, the system becomes:


1 = a1 + a2 + a3

0 = a1 - 2 * a2 - 5 * a3

0 = 6 * a2 + 30 * a3


with the solutions a1 = 5/9, a2 = 5/9, and a3 = -1/9, giving the second-order recursive function:


g(x) = 5/9 * x + (5 * k) / (9 * x^2) - k^2 / (9 * x^5)


The article shows the derivation of a third-order recursive function for both square and cube root. 


Deriving a Second-Order Algorithm for Quartic Roots


Let's use a similar approach used in Elgin's article to develop an algorithm to calculate the fourth (quartic) root:  


k^1/4 = x


Let f(x) = x^4 - k,  then f'(x) = 4*x^3, and


x_n+1 = x_n - (x_n^4 - k) / (4 * x_n^3) = 3/4 * x_n - k / (4 * x_n^3)


Use guesses x_n, k / (x_n^3), k^2 / (x_n^7), we set up the equations:


g(x) = a1 * x + a2 * k / x^3 + a3 * k^2 / x^7


g'(x) = a1 - 3 * a2 * k / x^4 - 7 * a3 * k^2 / x^8


g''(x) = 12 * a2 * k / x^5 + 56 * a3 * k^2 / x^9



Setting g(x) = x^1/4, g'(x) = 0, g''(x) = 0, and setting g(k^1/4), we get the system:


1 = a1 + a2 + a3

0 = a1 - 3 * a2 - 7 * a3

0 = 12 * a2 + 56 * a3


The solutions to above system:  a1 = 21/32, a2 = 7/16, a3 = -3/32, which gives the second order recursive  equation:


g(x) = 21/32 * x + (7 * k) / (32 * x^3) - (3 * k) / (32 * x^7)

 

The program FTHROOT use the recursive equation to approximate the quartic root. 



HP Prime Program:  FTHROOT


EXPORT FTHROOT(k)

BEGIN

// EWS 2020-10-21

// Approx 4th Root

LOCAL r,r0,r1,ri;

r:=k^0.25;

r0:=0; 

r1:=√k;

ri:=0;

WHILE ABS(r0-r1)>1ᴇ−10 DO

ri:=ri+1;

r0:=r1;

r1:=(21*r0)/32+(7*k)/(16*r0^3)-(3*k^2)/(32*r0^7);

END;

PRINT();

PRINT("4√"+PRINT(k));

PRINT("Root = "+STRING(r));

PRINT("------");

PRINT("Approximation: "+

STRING(r1));

PRINT("Iterations: "+STRING(ri));


END;


The choice of a good first guess is necessary with any iterative root finding process. The program FTHROOT chooses the square root of k for an initial guess.   The goal is to seek a positive root.


Examples


Each example is followed by a set of screen shots, which include setting up Sequences and their graphs on the HP Prime.  


Example 1


k = 176.4

Result:  3.64438831256 (algorithm took 7 iterations with initial guess √176.4)



Example 2

k = 5525
Result:  8.62150472576 (algorithm took 9 iterations with initial guess √5525)




Source

Elgin, Dave.  "Square Root & Cube Root Algorithms"  The Mathematical Association.  Mathematics in School, Jan. 2006, Vol. 35, No. 1 pp. 30-31.  https://www.jstor.org/stable/30215863

Eddie

All original content copyright, © 2011-2020.  Edward Shore.   Unauthorized use and/or unauthorized distribution for commercial purposes without express and written permission from the author is strictly prohibited.  This blog entry may be distributed for noncommercial purposes, provided that full credit is given to the author. 



Sunday, November 1, 2020

Book Review: Calculus for Middle Schoolers by Serena Swegle

 Book Review: Calculus for Middle Schoolers by Serena Swegle


Just The Facts


Calculus for Middle Schoolers


Author:  Serena Swegle


Publisher:  Sunhut Publishing


Cost:  $26.50 for Paperback, $9.99 for Kindle (as of 10/23/2020)


Link:  https://www.amazon.com/Calculus-Middle-Schoolers-Serena-Swegle/dp/057871275X/ref=sr_1_3?dchild=1&keywords=Calculus+for+Middle+Schoolers&qid=1603471676&sr=8-3


Topics Covered


The number e (2.718281828...)


The common logarithm  (base 10)


The natural logarithm (base e)


Trig Functions (sine, cosine, tangent)


Sums 


Limits


Derivative - the derivative of a polynomial


Integral - the integral of a polynomial


The Derivative and Integral of e^x


An Introduction to Calculus 


The target audience is middle school students.  However, book serves as a great introduction to calculus for high school and college students who are taking calculus for the first time.  The book gives a simple, concrete introduction to various subjects, in an easy-to-read narrative.  Calculus is a complex subject, and this book allows readers, who may be intimidated about the subject, to develop a understanding.   


I would recommend this book to be read prior to the student's first calculus class.   The book can be read in one or two days, but I feel it was meant to read as one chapter a time per day or week.   


Verdict


Swegle's book is well written, in a concise language.  The chapter covers one concept at the time, which serves as a great introduction to a rich subject.   The examples are simple and apply closely to the text.   I wish Swegle put a summary of all the topics covered at the end of the book as a wrap up.  Otherwise, I recommend this book for educators and parents.   For those who have the Kindle app, $9.99 is a good price point.  Recommended.


Thank you, Serena for recommending this book for me to review.  


Eddie


All original content copyright, © 2011-2020.  Edward Shore.   Unauthorized use and/or unauthorized distribution for commercial purposes without express and written permission from the author is strictly prohibited.  This blog entry may be distributed for noncommercial purposes, provided that full credit is given to the author.