#set document(title: "2.4 Floating-point errors", author: "OpenStax / XYZ Homework") #set page(width: 8.5in, height: auto, margin: 1in) #import "@preview/cetz:0.5.2" #set text(font: ("STIX Two Text", "Libertinus Serif", "New Computer Modern"), size: 10.5pt, lang: "en") #show math.equation: set text(font: ("STIX Two Math", "New Computer Modern Math")) #set par(justify: true, leading: 0.62em, spacing: 0.9em) #set enum(spacing: 1.1em) // room between list items so tall inline fractions don't collide #set list(spacing: 1.1em) #set table(stroke: 0.5pt + rgb("#c7ccd3")) #let BLUE = rgb("#183B6F") // brand navy — section bars + example/solution labels (white on navy 11.09:1) #let ORANGE = rgb("#A94509") // brand primary-700 — AA-safe deep orange for TEXT (5.93:1 on white; raw brand #F37021 is 2.94:1 and must never carry text) #let RED = rgb("#DC2626") // brand error-600 #let GREEN = rgb("#059669") // brand success-600 (decoration only; small green text uses green-text #007942) #show heading.where(level: 1): it => block(width: 100%, above: 0pt, below: 16pt, fill: gradient.linear(BLUE, rgb("#2C5AA0")), inset: (x: 14pt, y: 12pt), radius: 3pt, text(fill: white, weight: "bold", size: 19pt, it.body)) #show heading.where(level: 2): it => block(width: 100%, above: 18pt, below: 10pt, fill: BLUE, inset: (x: 10pt, y: 6pt), radius: 2pt, text(fill: white, weight: "bold", size: 12pt, it.body)) #show heading.where(level: 3): it => text(fill: ORANGE, weight: "bold", size: 12.5pt, it.body) #show heading.where(level: 4): it => text(fill: BLUE, weight: "bold", size: 10.5pt, it.body) #let examplebox(label, title, body) = block(width: 100%, breakable: true, fill: rgb("#EFF1F5"), stroke: 0.5pt + rgb("#CFDDF0"), radius: 4pt, inset: 10pt, above: 12pt, below: 12pt)[ #block(below: 6pt)[#box(fill: BLUE, inset: (x: 6pt, y: 2pt), radius: 2pt, text(fill: white, weight: "bold", size: 8.5pt, label)) #h(0.4em) #strong[#title]] #body] // rail = decorative left rule (raw brand token); labelcolor = AA-safe label text shade #let notebox(label, rail, labelcolor, tint, body) = block(width: 100%, breakable: true, fill: tint, stroke: (left: 3pt + rail), inset: (left: 10pt, rest: 8pt), radius: (right: 4pt), above: 11pt, below: 11pt)[ #text(fill: labelcolor, weight: "bold", size: 7.5pt, tracking: 0.5pt)[#upper(label)] #linebreak() #body] #let solutionbox(body) = block(above: 4pt, below: 8pt)[ #text(fill: BLUE, weight: "bold", size: 8.5pt)[Solution] #linebreak() #body] #let figph(msg) = block(width: 100%, height: 60pt, fill: rgb("#f6f7f9"), stroke: (paint: rgb("#c7ccd3"), dash: "dashed"), radius: 4pt, inset: 10pt)[ #align(center + horizon, text(fill: rgb("#889"), style: "italic", size: 9pt, msg))] // Standardize inlined figure sizes: measure the natural CeTZ canvas, then scale to a // consistent envelope (aspect-aware; see build_typst.py FIG_* constants). Unlike the // print preamble, dimensions are FLOORED: in an editor a user can trim a figure to a // degenerate 1-D shape (a bare line), and w/h or tw/w would then divide by zero. #let _STD_W = 3.5 #let _WIDE_W = 5.6 #let _MAX_H = 3.4 #let _ASPECT_WIDE = 2.2 #let _UPSCALE_MAX = 1.15 #let stdfig(body) = context { let m = measure(body) let w = calc.max(m.width / 1in, 0.01) let h = calc.max(m.height / 1in, 0.01) let tw = if w / h > _ASPECT_WIDE { _WIDE_W } else { _STD_W } let s = calc.min(tw / w, _MAX_H / h, _UPSCALE_MAX) align(center, box(scale(x: s * 100%, y: s * 100%, reflow: true, body))) } #show figure: set block(breakable: false) #set figure(gap: 8pt) #show figure.caption: set text(size: 8.5pt, fill: rgb("#555")) == 2.4#h(0.6em)Floating-point errors === Learning objectives By the end of this section you should be able to - Explain numerical inaccuracies related to floating-point representation. - Use the round() function to mitigate floating-point errors in output. === Floating-point errors Computers store information using 0's and 1's. All information must be converted to a string of 0's and 1's. Ex: 5 is converted to 101. Since only two values, 0 or 1, are allowed the format is called binary. Floating-point values are stored as binary by Python. The conversion of a floating point number to the underlying binary results in specific types of floating-point errors. A #strong[round-off error] occurs when floating-point values are stored erroneously as an approximation. The difference between an approximation of a value used in computation and the correct (true) value is called a round-off error. Ex: Storing the float (0.1)#sub[10] results in binary values that actually produce (0.1000000000000000055511151231257827021181583404541015625)#sub[10] when converted back, which is not exactly equal to (0.1)#sub[10]. #figure(table( columns: 2, align: left, inset: 6pt, [\# Print floats with 30 decimal places print(f'{0.1:.30f}') \# prints 0.1 print(f'{0.2:.30f}') \# prints 0.2 print(f'{0.4:.30f}') \# prints 0.4], [0.100000000000000005551115123126 0.200000000000000011102230246252 0.400000000000000022204460492503], )) An #strong[overflow error] occurs when a value is too large to be stored. The maximum and minimum floating-point values that can be represented are #math.equation(block: false, alt: "1 .8 times 10 to the power 308")[$"1" ".8" × 10^(308)$] and #math.equation(block: false, alt: "minus 1.8 times 10 to the power 308")[$− 1.8 × 10^(308)$], respectively. Attempting to store a floating-point value outside the range #math.equation(block: false, alt: "open parenthesis minus 1.8 times 10 to the power 308 , 1.8 times 10 to the power 308 close parenthesis")[$( − 1.8 × 10^(308) , 1.8 × 10^(308) )$] leads to an overflow error. Below, #math.equation(block: false, alt: "3 .0 to the power 256")[$"3" ".0"^(256)$] and #math.equation(block: false, alt: "3 .0 to the power 512")[$"3" ".0"^(512)$] can be represented, but #math.equation(block: false, alt: "3 .0 to the power 1024")[$"3" ".0"^(1024)$] is too large and causes an overflow error. #figure(table( columns: 2, align: left, inset: 6pt, [print('3.0 to the power of 256 =', 3.0\*\*256) print('3.0 to the power of 512 = ', 3.0\*\*512) print('3.0 to the power of 1024 = ', 3.0\*\*1024)], [3.0 to the power of 256 = 1.3900845237714473e+122 3.0 to the power of 512 = 1.9323349832288915e+244 3.0 to the power of 1024 = Traceback (most recent call last):   File "\", line 3, in \     print('3.0 to the power of 1024 = ', 3.0\*\*1024) OverflowError: (34, 'Numerical result out of range')], )) #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ #emph[Floating-point errors] For each situation, which error occurs? ] === Floating point round() function Python's #strong[round()] function is used to round a floating-point number to a given number of decimal places. The function requires two arguments. The first argument is the number to be rounded. The second argument decides the number of decimal places to which the number is rounded. If the second argument is not provided, the number will be rounded to the closest integer. The round() function can be used to mitigate floating-point errors. Ex: - round(2.451, 2) = 2.45 - round(2.451) = 2 #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ #emph[Examples of round() function] #link("https://www.openstax.org/r/round-function")[Examples of a round function; ch 2, video 7] ] #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ #emph[Examples of round() function] ] #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ #emph[Inaccurate tips] The following code calculates the tip amount, given a bill amount and the tip ratio. Experiment with the following bill amounts and tip ratios and see if any inaccuracies may result in calculating the tip amount. - bill amount: 22.70 and 33.33 - tip ratio: 0.15, 0.18, and 0.20 bill = 15 tip\_ratio = 0.1 tip\_amount = tip\_ratio \* bill print("Tip =", tip\_amount) ] #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ #emph[Area of a triangle] Complete the following steps to calculate a triangle's area, and print the result of each step. The area of a triangle is #math.equation(block: false, alt: "the fraction b h over 2")[$frac(b h, 2)$], where #emph[b] is the base and #emph[h] is the height. + Calculate the area of a triangle with base = 7 and height = 3.5. + Round the triangle's area to one decimal place. + Round the triangle's area to the nearest integer value. base = 7 height = 3.5 \# TODO: Calculate area print("Step 1:", area) \# TODO: Round area to one decimal place print("Step 2:", area\_2) \# TODO: Round area to nearest integer print("Step 3:", area\_3) ]