<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Subtration correct, but by IF not correct? in SAS Programming</title>
    <link>https://communities.sas.com/t5/SAS-Programming/Subtration-correct-but-by-IF-not-correct/m-p/951768#M372024</link>
    <description>&lt;P&gt;Hi&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/463573"&gt;@Hoibai&lt;/a&gt;,&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;This is a typical example of rounding errors due to numeric representation issues: Most numeric values with decimal places don't have an exact finite binary representation. In your example, the &lt;A href="https://documentation.sas.com/doc/en/lrcon/9.4/p0ji1unv6thm0dn1gp4t01a1u0g6.htm#n130t9ze48hipcn0z60fuk5jb6pz" target="_blank" rel="noopener"&gt;internal binary 64-bit floating-point representations&lt;/A&gt; of both 1604202898189.95 and 168579411743.91 are affected by rounding errors. Doing arithmetic with rounded values is likely to produce a rounding error in the result as well. As a consequence, a very small difference occurs between expressions that &lt;EM&gt;would&lt;/EM&gt; be equal if the calculation was done in the decimal system (or with infinitely many bits in the binary system).&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The same effect can occur with much smaller numbers:&lt;/P&gt;
&lt;PRE&gt;11    data _null_;
12    if 1.86 ne 0.95 + 0.91 then put 'Surprised?';
13    run;

Surprised?
NOTE: DATA statement used (Total process time):
&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;To avoid those surprises, use the ROUND function with an appropriate rounding unit.&lt;/P&gt;
&lt;P&gt;Example:&lt;/P&gt;
&lt;PRE&gt;14    data _null_;
15    if 1772782309933.86 = round(1604202898189.95 + 168579411743.91, 0.01) then put 'OK';
16    run;

OK
NOTE: DATA statement used (Total process time):&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Here's how SAS computes the sum internally:&lt;/P&gt;
&lt;P&gt;Looking at the internal binary representations (&lt;A href="https://documentation.sas.com/doc/en/pgmsascdc/9.4_3.5/leforinforref/p1b6ugw71lmhnpn1wixijtysezzg.htm" target="_blank" rel="noopener"&gt;BINARY64. format&lt;/A&gt;) of&amp;nbsp;1604202898189.95 and&amp;nbsp;168579411743.91, we can write the sum mathematically in units of 2**40 in the binary system as follows:&lt;/P&gt;
&lt;PRE&gt;&lt;FONT size="4"&gt;&lt;STRONG&gt;&lt;FONT color="#3366FF"&gt;  1.0111010110000001111100011010001100001101&lt;/FONT&gt;11&lt;U&gt;1100&lt;/U&gt;110011&lt;/STRONG&gt;&lt;FONT color="#999999"&gt;001100110011001100110011001100...&lt;/FONT&gt;
&lt;STRONG&gt;+ &lt;FONT color="#3366FF"&gt;0.0010011101000000000111011010111100011111&lt;/FONT&gt;11&lt;U&gt;101000111101&lt;FONT color="#FF0000"&gt;1&lt;/FONT&gt;&lt;/U&gt;&lt;/STRONG&gt;&lt;FONT color="#999999"&gt;&lt;U&gt;1110000&lt;/U&gt;101000111101&lt;FONT color="#00FF00"&gt;0&lt;/FONT&gt;1110000...&lt;/FONT&gt;
&lt;STRONG&gt;= &lt;FONT color="#3366FF"&gt;1.1001110011000010000011110101001000101101&lt;/FONT&gt;110111000010&lt;FONT color="#999999"&gt;011&lt;/FONT&gt;&lt;/STRONG&gt;&lt;FONT color="#999999"&gt;(...)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/PRE&gt;
&lt;P&gt;The internal binary representations of numeric values (on Windows and Unix systems) use 52 mantissa bits plus one implied bit for the actual binary digits (while 11 bits are used for the exponent and 1 bit for the sign). In the first of the three lines above the 53 binary digits of&amp;nbsp;1604202898189.95 are shown in boldface: 41 of these, written in blue color, represent the integer part of the number, i.e.,&amp;nbsp;1604202898189. The remaining 12 bits represent the fractional part (.95) -- more precisely: only a small portion of the infinitely many binary digits needed for an exact representation. The bits that don't fit into the total width of 53 bits are written in medium gray color. You can see the repeating pattern "1100" (underlined) of the periodic fraction 1/5=0.2 (binary: 0.00110011001100...), which together with the 0.75 (binary: 0.11) forms the 0.95. So this number has been &lt;EM&gt;rounded off&lt;/EM&gt; internally.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The second line shows&amp;nbsp;168579411743.91 in a similar fashion. Note the three leading zeros due to the fact that the order of magnitude of this number is only 2**37 as opposed to 2**40. This allows for 53-38=15 bits representing the&amp;nbsp;fractional part (.91), written in black (and red). But, again, even 15 bits are totally insufficient to accommodate the infinitely many bits required for an exact representation. I have added so many of the lost digits in gray that the (underlined) repeating pattern&amp;nbsp;&lt;FONT face="courier new,courier"&gt;10100011110101110000&lt;/FONT&gt; (this time of length 20 rather than 4) can be recognized. Note, however, that the red "&lt;FONT face="courier new,courier" color="#FF0000"&gt;&lt;STRONG&gt;1&lt;/STRONG&gt;&lt;/FONT&gt;" is &lt;EM&gt;rounded up&lt;/EM&gt; from the original "&lt;FONT face="courier new,courier"&gt;0&lt;/FONT&gt;" (cf. the light green zero twenty digits later) because of the subsequent bits "&lt;FONT face="courier new,courier"&gt;11100&lt;/FONT&gt;...".&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Now we can start the addition (like in elementary school), the result of which is shown in the third line: Remember that the gray digits are lost due to rounding, i.e., they are replaced by zeros altogether. So the first calculation adds the red "&lt;FONT face="courier new,courier" color="#FF0000"&gt;&lt;STRONG&gt;1&lt;/STRONG&gt;&lt;/FONT&gt;" to the zero (which would be 1 without rounding) above it, resulting in the rightmost "&lt;FONT face="courier new,courier"&gt;1&lt;/FONT&gt;" in the third line, followed by another "&lt;FONT face="courier new,courier"&gt;0+1=1&lt;/FONT&gt;" for the bit left to it. The third-to-last bit is calculated as&amp;nbsp;&lt;FONT face="courier new,courier"&gt;0+0=0&lt;/FONT&gt;, the fourth-to-last bit as &lt;FONT face="courier new,courier"&gt;1+1=10&lt;/FONT&gt; (binary system!), resulting in the &lt;FONT face="courier new,courier"&gt;0&lt;/FONT&gt; (in the fourth-to-last bit of the third line) and a carryover of &lt;FONT face="courier new,courier"&gt;1&lt;/FONT&gt;, which adds to the "&lt;FONT face="courier new,courier"&gt;1+1&lt;/FONT&gt;" coming next, and so on.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Finally, the result is rounded to fit into the 52+1 available bits. In the example above the last three bits "&lt;FONT face="courier new,courier"&gt;011&lt;/FONT&gt;" (gray) are rounded off. This matches the result of&amp;nbsp;1604202898189.95+168579411743.91, written in BINARY64. format, &lt;EM&gt;but not&lt;/EM&gt; 1772782309933.86, written in BINARY64. format, which (in units of 2**40) would correspond to&lt;/P&gt;
&lt;PRE&gt;&lt;FONT size="4"&gt;&lt;FONT color="#3366FF"&gt;&lt;STRONG&gt;  1.1001110011000010000011110101001000101101&lt;/STRONG&gt;&lt;/FONT&gt;&lt;STRONG&gt;11011100001&lt;FONT color="#339966"&gt;1&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/PRE&gt;
&lt;P&gt;Obviously, the rounding errors coming from numeric representation in 64-bit floating-point format and from the calculation (rounding the result again) led to an incorrect least significant (i.e. rightmost) bit, representing 2**−12=0.000244140625 in this case. This is the "very small difference" mentioned earlier&amp;nbsp;(well, "very small" compared to the large numbers involved), which causes the IF condition to be FALSE.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Applying the ROUND function with a rounding unit of 0.01 or 0.001, much greater than that small difference, corrects the error.&lt;/P&gt;</description>
    <pubDate>Mon, 25 Nov 2024 14:07:33 GMT</pubDate>
    <dc:creator>FreelanceReinh</dc:creator>
    <dc:date>2024-11-25T14:07:33Z</dc:date>
    <item>
      <title>Subtration correct, but by IF not correct?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Subtration-correct-but-by-IF-not-correct/m-p/951760#M372021</link>
      <description>&lt;P&gt;Hi all,&lt;/P&gt;
&lt;P&gt;can you please explain to me why the values ​​are the same but it still ran into Else? Thanks.&lt;/P&gt;
&lt;P&gt;&lt;BR /&gt;MPRINT(QUARTAL_AUSGABE): &lt;STRONG&gt;if 1772782309933.86 = 1604202898189.95 + 168579411743.91 then do;&lt;/STRONG&gt;&lt;BR /&gt;MPRINT(QUARTAL_AUSGABE): put 'die Summenbildung fuer Wert ist korrekt, ';&lt;BR /&gt;MPRINT(QUARTAL_AUSGABE): end;&lt;BR /&gt;MPRINT(QUARTAL_AUSGABE): &lt;STRONG&gt;else do;&lt;/STRONG&gt;&lt;BR /&gt;MPRINT(QUARTAL_AUSGABE): put 'Regel S903 für Wert ist verletzt ';&lt;BR /&gt;MPRINT(QUARTAL_AUSGABE): end;&lt;BR /&gt;&lt;BR /&gt;&lt;/P&gt;</description>
      <pubDate>Mon, 25 Nov 2024 09:42:03 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Subtration-correct-but-by-IF-not-correct/m-p/951760#M372021</guid>
      <dc:creator>Hoibai</dc:creator>
      <dc:date>2024-11-25T09:42:03Z</dc:date>
    </item>
    <item>
      <title>Re: Subtration correct, but by IF not correct?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Subtration-correct-but-by-IF-not-correct/m-p/951768#M372024</link>
      <description>&lt;P&gt;Hi&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/463573"&gt;@Hoibai&lt;/a&gt;,&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;This is a typical example of rounding errors due to numeric representation issues: Most numeric values with decimal places don't have an exact finite binary representation. In your example, the &lt;A href="https://documentation.sas.com/doc/en/lrcon/9.4/p0ji1unv6thm0dn1gp4t01a1u0g6.htm#n130t9ze48hipcn0z60fuk5jb6pz" target="_blank" rel="noopener"&gt;internal binary 64-bit floating-point representations&lt;/A&gt; of both 1604202898189.95 and 168579411743.91 are affected by rounding errors. Doing arithmetic with rounded values is likely to produce a rounding error in the result as well. As a consequence, a very small difference occurs between expressions that &lt;EM&gt;would&lt;/EM&gt; be equal if the calculation was done in the decimal system (or with infinitely many bits in the binary system).&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The same effect can occur with much smaller numbers:&lt;/P&gt;
&lt;PRE&gt;11    data _null_;
12    if 1.86 ne 0.95 + 0.91 then put 'Surprised?';
13    run;

Surprised?
NOTE: DATA statement used (Total process time):
&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;To avoid those surprises, use the ROUND function with an appropriate rounding unit.&lt;/P&gt;
&lt;P&gt;Example:&lt;/P&gt;
&lt;PRE&gt;14    data _null_;
15    if 1772782309933.86 = round(1604202898189.95 + 168579411743.91, 0.01) then put 'OK';
16    run;

OK
NOTE: DATA statement used (Total process time):&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Here's how SAS computes the sum internally:&lt;/P&gt;
&lt;P&gt;Looking at the internal binary representations (&lt;A href="https://documentation.sas.com/doc/en/pgmsascdc/9.4_3.5/leforinforref/p1b6ugw71lmhnpn1wixijtysezzg.htm" target="_blank" rel="noopener"&gt;BINARY64. format&lt;/A&gt;) of&amp;nbsp;1604202898189.95 and&amp;nbsp;168579411743.91, we can write the sum mathematically in units of 2**40 in the binary system as follows:&lt;/P&gt;
&lt;PRE&gt;&lt;FONT size="4"&gt;&lt;STRONG&gt;&lt;FONT color="#3366FF"&gt;  1.0111010110000001111100011010001100001101&lt;/FONT&gt;11&lt;U&gt;1100&lt;/U&gt;110011&lt;/STRONG&gt;&lt;FONT color="#999999"&gt;001100110011001100110011001100...&lt;/FONT&gt;
&lt;STRONG&gt;+ &lt;FONT color="#3366FF"&gt;0.0010011101000000000111011010111100011111&lt;/FONT&gt;11&lt;U&gt;101000111101&lt;FONT color="#FF0000"&gt;1&lt;/FONT&gt;&lt;/U&gt;&lt;/STRONG&gt;&lt;FONT color="#999999"&gt;&lt;U&gt;1110000&lt;/U&gt;101000111101&lt;FONT color="#00FF00"&gt;0&lt;/FONT&gt;1110000...&lt;/FONT&gt;
&lt;STRONG&gt;= &lt;FONT color="#3366FF"&gt;1.1001110011000010000011110101001000101101&lt;/FONT&gt;110111000010&lt;FONT color="#999999"&gt;011&lt;/FONT&gt;&lt;/STRONG&gt;&lt;FONT color="#999999"&gt;(...)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/PRE&gt;
&lt;P&gt;The internal binary representations of numeric values (on Windows and Unix systems) use 52 mantissa bits plus one implied bit for the actual binary digits (while 11 bits are used for the exponent and 1 bit for the sign). In the first of the three lines above the 53 binary digits of&amp;nbsp;1604202898189.95 are shown in boldface: 41 of these, written in blue color, represent the integer part of the number, i.e.,&amp;nbsp;1604202898189. The remaining 12 bits represent the fractional part (.95) -- more precisely: only a small portion of the infinitely many binary digits needed for an exact representation. The bits that don't fit into the total width of 53 bits are written in medium gray color. You can see the repeating pattern "1100" (underlined) of the periodic fraction 1/5=0.2 (binary: 0.00110011001100...), which together with the 0.75 (binary: 0.11) forms the 0.95. So this number has been &lt;EM&gt;rounded off&lt;/EM&gt; internally.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The second line shows&amp;nbsp;168579411743.91 in a similar fashion. Note the three leading zeros due to the fact that the order of magnitude of this number is only 2**37 as opposed to 2**40. This allows for 53-38=15 bits representing the&amp;nbsp;fractional part (.91), written in black (and red). But, again, even 15 bits are totally insufficient to accommodate the infinitely many bits required for an exact representation. I have added so many of the lost digits in gray that the (underlined) repeating pattern&amp;nbsp;&lt;FONT face="courier new,courier"&gt;10100011110101110000&lt;/FONT&gt; (this time of length 20 rather than 4) can be recognized. Note, however, that the red "&lt;FONT face="courier new,courier" color="#FF0000"&gt;&lt;STRONG&gt;1&lt;/STRONG&gt;&lt;/FONT&gt;" is &lt;EM&gt;rounded up&lt;/EM&gt; from the original "&lt;FONT face="courier new,courier"&gt;0&lt;/FONT&gt;" (cf. the light green zero twenty digits later) because of the subsequent bits "&lt;FONT face="courier new,courier"&gt;11100&lt;/FONT&gt;...".&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Now we can start the addition (like in elementary school), the result of which is shown in the third line: Remember that the gray digits are lost due to rounding, i.e., they are replaced by zeros altogether. So the first calculation adds the red "&lt;FONT face="courier new,courier" color="#FF0000"&gt;&lt;STRONG&gt;1&lt;/STRONG&gt;&lt;/FONT&gt;" to the zero (which would be 1 without rounding) above it, resulting in the rightmost "&lt;FONT face="courier new,courier"&gt;1&lt;/FONT&gt;" in the third line, followed by another "&lt;FONT face="courier new,courier"&gt;0+1=1&lt;/FONT&gt;" for the bit left to it. The third-to-last bit is calculated as&amp;nbsp;&lt;FONT face="courier new,courier"&gt;0+0=0&lt;/FONT&gt;, the fourth-to-last bit as &lt;FONT face="courier new,courier"&gt;1+1=10&lt;/FONT&gt; (binary system!), resulting in the &lt;FONT face="courier new,courier"&gt;0&lt;/FONT&gt; (in the fourth-to-last bit of the third line) and a carryover of &lt;FONT face="courier new,courier"&gt;1&lt;/FONT&gt;, which adds to the "&lt;FONT face="courier new,courier"&gt;1+1&lt;/FONT&gt;" coming next, and so on.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Finally, the result is rounded to fit into the 52+1 available bits. In the example above the last three bits "&lt;FONT face="courier new,courier"&gt;011&lt;/FONT&gt;" (gray) are rounded off. This matches the result of&amp;nbsp;1604202898189.95+168579411743.91, written in BINARY64. format, &lt;EM&gt;but not&lt;/EM&gt; 1772782309933.86, written in BINARY64. format, which (in units of 2**40) would correspond to&lt;/P&gt;
&lt;PRE&gt;&lt;FONT size="4"&gt;&lt;FONT color="#3366FF"&gt;&lt;STRONG&gt;  1.1001110011000010000011110101001000101101&lt;/STRONG&gt;&lt;/FONT&gt;&lt;STRONG&gt;11011100001&lt;FONT color="#339966"&gt;1&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/PRE&gt;
&lt;P&gt;Obviously, the rounding errors coming from numeric representation in 64-bit floating-point format and from the calculation (rounding the result again) led to an incorrect least significant (i.e. rightmost) bit, representing 2**−12=0.000244140625 in this case. This is the "very small difference" mentioned earlier&amp;nbsp;(well, "very small" compared to the large numbers involved), which causes the IF condition to be FALSE.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Applying the ROUND function with a rounding unit of 0.01 or 0.001, much greater than that small difference, corrects the error.&lt;/P&gt;</description>
      <pubDate>Mon, 25 Nov 2024 14:07:33 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Subtration-correct-but-by-IF-not-correct/m-p/951768#M372024</guid>
      <dc:creator>FreelanceReinh</dc:creator>
      <dc:date>2024-11-25T14:07:33Z</dc:date>
    </item>
    <item>
      <title>Re: Subtration correct, but by IF not correct?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Subtration-correct-but-by-IF-not-correct/m-p/951823#M372055</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/463573"&gt;@Hoibai&lt;/a&gt;&amp;nbsp;:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Please note that&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/32733"&gt;@FreelanceReinh&lt;/a&gt;'s explanation is &lt;EM&gt;&lt;STRONG&gt;not an exclusively SAS issue&lt;/STRONG&gt;&lt;/EM&gt;.&amp;nbsp; It is an issue for all&amp;nbsp; software on digital computers based on binary arithmetic.&lt;/P&gt;</description>
      <pubDate>Mon, 25 Nov 2024 16:23:35 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Subtration-correct-but-by-IF-not-correct/m-p/951823#M372055</guid>
      <dc:creator>mkeintz</dc:creator>
      <dc:date>2024-11-25T16:23:35Z</dc:date>
    </item>
  </channel>
</rss>

