Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
881 views
in Technique[技术] by (71.8m points)

math - How can I make a "working" repeating decimal representation of a rational number?

I've figured out how to display the repeating part of a repeating decimal using OverBar.

repeatingDecimal doesn't actually work as a repeating decimal. I'd like to make a variation of it that looks and behaves like a repeating decimal.


Question

How could I make a working repeating decimal representation (possibly using Interpretation[])?


Background

Please excuse me if I ramble. This is my first question and I wanted to be clear about what I have in mind.

The following will "draw" a repeating decimal.

repeatingDecimal[q2_] :=
 Module[{a},
  a[{{nr__Integer}, pt_}] := 
   StringJoin[
    Map[ToString, 
     If[pt > -1, Insert[{nr}, ".", pt + 1], 
      Join[{"."}, Table["0", {Abs[pt]}], {nr}]]]];
  (* repeating only *)

  a[{{{r__Integer}}, pt_}] := 
   Row[{".", OverBar@StringJoin[Map[ToString, {r}]]}];

  (* One or more non-repeating; 
  more than one repeating digit KEEP IN THIS ORDER!! *)
  a[{{nr__, {r__}}, pt_}] := 
   Row[{StringJoin[
      Map[ToString, 
       If[pt > -1, Insert[{nr}, ".", pt + 1], 
        Join[{"."}, Table["0", {Abs[pt]}], {nr}]]]], 
     OverBar@StringJoin[Map[ToString, {r}]]}];
  (* One or more non-repeating; one repeating digit *)

  a[{{nr__, r_Integer}, pt_}] := 
   Row[{StringJoin[Map[ToString, {nr}]], ".", 
     OverBar@StringJoin[Map[ToString, r]]}];
  a[RealDigits[q2]]]

So

repeatingDecimal[7/31]

displays a repeating decimal properly (shown here as a picture so that the OverBar appears).

Repeating decimal displayed

Looking under the hood, it's really just an imposter, an image of a repeating decimal ...

In[]:= repeatingDecimal[7/31]//FullForm
Out[]:= Row[List[".",OverBar["225806451612903"]]]

Of course, it doesn't behave like a number:

% + 24/31

fraction plus repeating decimal

I'd like the addition to yield: 1


Edit: A cleaned up version of repeatingDecimal

Leonid showed how to wrap Format around the routine and to supply up-values for adding and multiplying repeated decimals. Very helpful! It will take some time for me to be comfortable with up and down values.

What follows below is essentially the streamlined version of the code suggested by Mr.Wizard. I set the OverBar above each repeating digit to allow line-breaking. (A single OverBar above Row looks tidier but cannot break when the right screen-margin is reached.)

ClearAll[repeatingDecimal]

repeatingDecimal[n_Integer | n_Real] := n

Format[repeatingDecimal[q_Rational]] := Row @ Flatten[
   {IntegerPart@q, ".", RealDigits@FractionalPart@q} /.
    {{nr___Integer, r_List: {}}, pt_} :> {Table[0, {-pt}], nr, OverBar /@ r}
  ]

repeatingDecimal[q_] + x_ ^:= q + x
repeatingDecimal[q_] * x_ ^:= q * x
repeatingDecimal[q_] ^ x_ ^:= q ^ x

The table below shows some output from repeatingDecimal:

n1 = 1; n2 = 15; ClearAll[i, k, r];
TableForm[Table[repeatingDecimal[i/j], {i, n1, n2}, {j, n1, n2}], 
TableHeadings -> {None, Table[("r")/k, {k, n1, n2}]}]

enter image description here


Checking the solution: Operating with repeating decimals

Let's now check the addition and multiplication of repeating decimals:

a = repeatingDecimal[7/31];
b = repeatingDecimal[24/31];
Print["a = ", a]
Print["b = ", b]
Print["a + b = ", a, " + ", b, " = ", a + b]
Print["7/31 [Times] 24/31 = " , (7/31)* (24/31)]
Print["a[Times]b = ", a*b, " = 
", repeatingDecimal[a*b]]
Print[N[168/961, 465]]

repeating decimal addition and multiplication

So addition and multiplication of repeating decimals work as desired. Power also appears to work properly.

Notice that 168/961 occupies 465 places to the right of the decimal point. After that, it starts to repeat. The results match those of N[168/961, 465], except for the OverBar, although line-breaks occur at different places. And, as is to be expected, this jibes with the following:

digits = RealDigits[168/961]
Length[digits[[1, 1]]]

465 digits


Some effects of the Format[] wrapper on the behavior of N[] in summing repeated decimals

Mr.Wizard suggested that the Format wrapper is superfluous for the cases of Integers and Reals.

Let's consider how the following two additions

repeatingDecimal[7/31] + repeatingDecimal[24/31]
N@repeatingDecimal[7/31] + N@repeatingDecimal[24/31]

behave in four different cases:

Case 1: Results when Format wrapped around repeatingDecimals for Reals and Integers and up values are ON

Case 1

As expected, the first addition yields an integer, the second a decimal.


Case 2: Results when Format NOT wrapped around repeatingDecimals for Reals and Integers but up values are ON

Case 2

The Format wrapper around Reals and Integers doesn't affect the additions at hand.


Case 3: Results when Format wrapped around repeatingDecimals for Reals and Integers but up values are OFF

Case 3

If upvalues are OFF, Format prevents addition from happening.


Case 4: Results when Format NOT wrapped around repeatingDecimals for Reals and Integers and up values are OFF

Case 4

If upvalues are OFF and Format` NOT wrapped around repeatingDecimals for Reals and Integers , the second addition works as expected.

All the more reason to remove the Format wrapper for the case of reals and integers.


Anyone have any remarks about the different outcomes in Cases 3 and 4?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You shouldn't have given your repeatingDecimal DownVaues, but rather, FormatValues:

ClearAll[repeatingDecimal];
Format[repeatingDecimal[q2_]] := 
Module[{a}, 
 a[{{nr__Integer}, pt_}] := 
 StringJoin[
  Map[ToString, 
   If[pt > -1, Insert[{nr}, ".", pt + 1], 
  Join[{"."}, Table["0", {Abs[pt]}], {nr}]]]];
  (*repeating only*)
 a[{{{r__Integer}}, pt_}] := 
 Row[{".", OverBar@StringJoin[Map[ToString, {r}]]}];
(*One or more non-repeating;
more than one repeating digit KEEP IN THIS ORDER!!*)
a[{{nr__, {r__}}, pt_}] := 
 Row[{StringJoin[
   Map[ToString, 
    If[pt > -1, Insert[{nr}, ".", pt + 1], 
     Join[{"."}, Table["0", {Abs[pt]}], {nr}]]]], 
  OverBar@StringJoin[Map[ToString, {r}]]}];
(*One or more non-repeating;one repeating digit*)
a[{{nr__, r_Integer}, pt_}] := 
  Row[{StringJoin[Map[ToString, {nr}]], ".", 
   OverBar@StringJoin[Map[ToString, r]]}];
a[RealDigits[q2]]]

Then, you can give it also UpValues, to integrate with common functions, for example:

repeatingDecimal /: Plus[left___, repeatingDecimal[q_], right___] := left + q + right;
repeatingDecimal /: Times[left___, repeatingDecimal[q_], right___] :=  left * q * right;

Then, for example,

In[146]:= repeatingDecimal[7/31]+24/31

Out[146]= 1

You can extend this approach to other common functions which you may want to work with repeatingDecimal.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...