我道歉。这个问题是编程任务的一部分。我们被要求实施 一种方法,将分数 f从基数A更改为基数B,精度为P位。 该功能有签名
baseChanger(int[] f, int A, int B, int P)
。
例如,小数3.14159的分数为0.14159,表示为数组:
int[] frac = {1,4,1,5,9};
基数为16的分数 - 0.3BA07 - 将被写入
int[] frac = {3,11,10,0,7};
转换为小数的二进制分数0.01为0.25,转换函数的测试如下所示:
int[] from = {0,1};
int[] to = {2,5};
@Test
assertArrayEquals(to, baseChanger(from, 2, 10, 2));
这是我们要求实施的算法:
/*
* for (i < P) {
* 1. Keep a carry, initialize to 0.
* 2. From right to left:
* a. x = multiply the ith digit by B and add the carry
* b. the new ith digit is x % A
* c. carry = x / A
* 3. output[i] = carry
*
* @param f The input array to translate. This array is not mutated.
* @param A The base that the input array is expressed in.
* @param B The base to translate into.
* @param P The number of digits of precision the output should
* have.
* @return An array of size P expressing digits in B.
*/
因此,如上所述,使用“from”和“to”,这意味着要执行以下操作:
创建一个可以容纳P位数的数组:
int [] output = new int [P]; // output = {0,0}
取“from”的最右边数字:
{0,1&lt; ==}
将该数字乘以B(此处为10)并添加进位(零,当前),并分配给x:
x < - 1 x 10 + 0 = 10
用x mod A(此处为2)替换最右边的数字(当前为1):
{0, 0 &lt; ==}
计算进位,即x / A:
携带&lt; - 10/2 = 5
将进位分配给输出中的第0个插槽:
输出[0]&lt; - carry
输出:{ 5 &lt; ==,0}
此过程再次重复,现在输出
output: {2,5}
但请注意,数字的顺序错误,并从最不重要的输出到最重要的!
另外,(更重要的是),从0.3等十进制分数到二进制的转换会怎样?假设您想要12位数的精度。当然,没有确切的二进制表示,所以你会在这里做什么,特别是因为最低有效数字出现第一?
from = {3}
我不知道从哪里开始,并希望得到一些建议。请记住,这些数字是分数,而不是整数,算法必须在线性时间内完成。
答案 0 :(得分:4)
免责声明:我认为它在 O(N)时间内完成。我已经添加了算法的多功能性。此外,负基数是IMPRACTICAL
以下方法将十进制基数中的数字转换为radix
中提到的数字:
/**
* This method returns an array with <code>precs</code> elements conating the
* required fractional part in the base <code>radix</code>
*
* @param frac A <code>float</code> that contains the fractional part
* (and fractional part only!!) in decimal number system.
* @param radix The base to which it has to be converted (must be (+) ve).
* @param precs The number of digits required i.e. precision.
*
* @return A <code>int[]</code> that contains the digits(eqivalent).
*/
public static int[] toRadix(float frac, int radix, int precs)
{
if(radix < 2) return null;
//Only fractional part is accepted here.
frac = frac - (long)frac; //Precautionary measure :-)
int i, j;
int[] res = new int[precs]; //For storing result.
for(i = 0; i < precs && frac != 0; i++)
{
frac *= radix;
res[i] = (int)frac;
if((long)frac >= 1)
frac = frac - (long)frac;
}
if(flag)
return copy(res, i);
return res;
}
将基数radix
中的数字转换为小数的方法会返回float
。
/**
* This method returns a <code>float</code> that contains the equivalent of the
* fraction in the other base in the parameter array, in decimal.
*
* @param frac An <code>int[]</code> conatining only the fractional part.
* @param radix The base of the fraction entered (must be (+) ve).
*
* @return The equivalent decimal fraction as a <code>float</code>.
*/
public static float toDecimal(int[] frac, int radix)
{
if(radix < 2) return null;
float res = 0, fac = 1.0f/radix;
int i, p = frac.length;
for(i = 0; i < p; i++)
{
res += frac[i] * fac; //or (float)Math.pow(radix, -i);
fac/=radix; //would be fine as well.
}
return res;
}
public static int[] baseChanger(int[] f, int A, int B, int P)
{
if(A < 2) return null;
if(B < 2) return null;
return toRadix(toDecimal(f, A), B, P);
}
copy
方法:
private static int[] copy(int[] a, int index)
{
index = index < a.length ? index : a.length;
int b[] = new int[index];
for(int i = 0; i < index; i++)
b[i] = a[i];
return b;
}
我已经获得了所需的泛化水平。结果:
实际(正确)输出:
上述代码的输出:
所以,我想这就解决了!顺便说一下,这里有一些提示:
使用数组而不是String
可能导致数组
并发症。对于初学者来说,float
的组成部分
输入很难处理。这个方法好的
对于小数部分,因为我们知道循环的位置
停止。
使用String
排除复制的需要。
但是你的方法有一个高手:radix
的上限是
Integer.MAX_VALUE
String
方法只有36 {0到9和a到
z)(虽然这不是一个非常严重的优点,因为它没有实际应用)。
更改数字基数的最实用方法是首先转换为 十进制和然后,将其转换为另一个基础。
使用double
会比使用float
更好,因为它可以提高准确性。
答案 1 :(得分:2)
此解决方案似乎有效。它在O(NP)时间内运行并且没有溢出(因为进位具有最大B-1 = 2 ^ 31-1-1)。如果你能打破它,请告诉我;请参阅下面的测试用例。
public class BaseTranslator {
public static int[] convertBase(int[] f, int A, int B, int P)
{
if(A < 2) return null;
if(B < 2) return null;
if(P < 1) return null;
if (f==null) return null;
int[] converted = new int[P];
int N = f.length;
for (int i=0; i<N; i++) if (f[i]<0 || f[i]>=A) return null;
int[] copy = new int[N];
for (int i=0;i<N;i++) {copy[i]=f[i];}
int i = 0;
for (i=0; i<P;i++) {
int carry=0;
for(int idx=N-1; idx>=0; idx--) {
int x = copy[idx]*B + carry;
int next = x % A;
carry = x / A;
copy[idx] = next;
}
converted[i]=carry;
}
return converted;
}
}
以下@Tests通过了:
import static org.junit.Assert.*;
import org.junit.Test;
public class BaseTranslatorTest {
@Test
public void basicBaseTranslatorTest() {
// Expect that .01 in base-2 is .25 in base-10
// (0 * 1/2^1 + 1 * 1/2^2 = .25)
// corners
/*
* If digits[i] < 0 or digits[i] >= baseA for any i, return null
* If baseA < 2, baseB < 2, or precisionB < 1, return null
*/
int[] input = {1};
assertArrayEquals(new int[]{1}, BaseTranslator.convertBase(input, 2, 2, 1));
// bad base and/or precision
assertArrayEquals(null, BaseTranslator.convertBase(input, 2, 2, 0));
assertArrayEquals(null, BaseTranslator.convertBase(input, 2, 1, 1));
assertArrayEquals(null, BaseTranslator.convertBase(input, 2, 1, 0));
assertArrayEquals(null, BaseTranslator.convertBase(input, 1, 2, 1));
assertArrayEquals(null, BaseTranslator.convertBase(input, 1, 2, 0));
assertArrayEquals(null, BaseTranslator.convertBase(input, 1, 1, 1));
assertArrayEquals(null, BaseTranslator.convertBase(input, 1, 1, 0));
// bad input
assertArrayEquals(null, BaseTranslator.convertBase(new int[]{9,3,5,-2}, 10, 10, 1));
assertArrayEquals(null, BaseTranslator.convertBase(new int[]{9,3,5, 2}, 9, 9, 1));
// null input
assertArrayEquals(null, BaseTranslator.convertBase(null, 1000000007, 1000000007, 1));
input = new int[]{0, 1};
int[] expectedOutput = {2, 5};
assertArrayEquals(expectedOutput, BaseTranslator.convertBase(input, 2, 10, 2));
assertArrayEquals(new int[]{0,1}, BaseTranslator.convertBase(new int[]{0,1}, 2, 2, 2));
assertArrayEquals(new int[]{0,1,0,0,0}, BaseTranslator.convertBase(new int[]{0,1}, 2, 2, 5));
assertArrayEquals(new int[]{0}, BaseTranslator.convertBase(new int[]{0,1}, 2, 2, 1));
assertArrayEquals(new int[]{2,5}, BaseTranslator.convertBase(new int[]{0,1}, 2, 10, 2));
assertArrayEquals(new int[]{2,5,0,0,0}, BaseTranslator.convertBase(new int[]{0,1}, 2, 10, 5));
assertArrayEquals(new int[]{2}, BaseTranslator.convertBase(new int[]{0,1}, 2, 10, 1));
assertArrayEquals(new int[]{0,1}, BaseTranslator.convertBase(new int[]{2,5}, 10, 2, 2));
assertArrayEquals(new int[]{0,1,0,0,0}, BaseTranslator.convertBase(new int[]{2,5}, 10, 2, 5));
assertArrayEquals(new int[]{0}, BaseTranslator.convertBase(new int[]{2,5}, 10, 2, 1));
assertArrayEquals(new int[]{0,0,0,0,0}, BaseTranslator.convertBase(new int[]{0}, 1000000007, 314159, 5));
assertArrayEquals(new int[]{1,1}, BaseTranslator.convertBase(new int[]{3,1,2,5}, 10, 4, 2));
assertArrayEquals(new int[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
BaseTranslator.convertBase(new int[]{0,0,0,0,3,0,5,1,7,5,7,8,1,2,5}, 10, 2, 15));
assertArrayEquals(new int[]{4,8,1,4,8,1,4,8,1,4,8,1,4,8,1,4,8},
BaseTranslator.convertBase(new int[]{1,1,1}, 3, 10, 17));
assertArrayEquals(new int[]{12},
BaseTranslator.convertBase(new int[]{12}, 16, 16, 1));
}
}