格式双作为分数
回答
您可能遇到的一个问题是,并非所有的小数值都可以用双打来表示。甚至一些看起来很简单的值,比如0.1。现在使用伪代码算法。您可能最好确定一英寸的第64个数,但将小数部分除以0.015625。之后,您可以将分数降至最低公分母。但是,由于您声明的是英寸,因此您可能不想使用最小公分母,而只使用英寸通常表示的值,2,4,8,16,32,64。
然而,有一点需要指出的是,由于您使用的是英寸,如果这些值都是一英寸的合适分数,并且分母为2,4,8,16,32,64,则该值永远不会包含浮点错误,因为分母总是2的幂。然而,如果你的数据集中有0.1英寸的值,那么你将开始遇到问题。
我不一定同意,基于Milhous希望覆盖英寸高达1/64的事实“假设程序始终要求1/64”的精度,那应该占用6位的尾数。在一个浮点数中,有24-6 = 18,(如果我的数学正确的话)应该表示他有一个+/- 262144 + 63/64的范围“
这可能足够精确地浮动到正确转换成派系没有损失。
而且,因为大多数人在工作英寸的采用2的幂的分母,它应该是罚款。
但是,回到原来的问题,我不知道任何库,
在一个名为LPC的C变体中的函数如下所示:注意:
- 在开始时增加输入值是为了解决精度问题,否则它们很容易告诉你5是4 999999/1000000。
- to_int()函数截断为整数。
- 语言有一个to_string()会将一些浮点数转换为指数表示法。
string strfrac(float frac) {
int main = to_int(frac + frac/1000000.0);
string out = to_string(main);
float rem = frac - to_float(main);
string rep;
if(rem > 0 && (to_int(rep = to_string(rem)) || member(rep, 'e') == Null)) {
int array primes = ({ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47 });
string base;
int exp;
int num;
int div;
if(sscanf(rep, "%se%d", base, exp) == 2) {
num = to_int(replace(base, ".", ""));
div = to_int(pow(10, abs(exp)));
} else {
rep = rep[2..];
num = to_int(rep);
div = to_int(pow(10, strlen(rep)));
}
foreach(int prime : primes) {
if(prime > num)
break;
while((num/prime) * prime == num && (div/prime) * prime == div) {
num /= prime;
div /= prime;
}
}
out += " " + num + "/" + div;
}
return out;
}
你的问题很简单,因为你放心分母将始终在C#中除以64,(有人随意翻译一个Java版本):
string ToMixedFraction(decimal x)
{
int whole = (int) x;
int denominator = 64;
int numerator = (int)((x - whole) * denominator);
if (numerator == 0)
{
return whole.ToString();
}
while (numerator % 2 == 0) // simplify fraction
{
numerator /= 2;
denominator /=2;
}
return string.Format("{0} {1}/{2}", whole, numerator, denominator);
}
奖励:代码高尔夫
public static string ToMixedFraction(decimal x) {
int w = (int)x,
n = (int)(x * 64) % 64,
a = n & -n;
return w + (n == 0 ? "" : " " + n/a + "/" + 64/a);
}
我的代码看起来像这样。
public static int gcd(int a, int b)
{
if (b == 0)
return a;
else
return gcd(b, a % b);
}
public static String doubleToStringFraction(Double d)
{
StringBuffer result = new StringBuffer(" " + ((int) Math.floor(d)));
int whole = (int) ((d - Math.floor(d)) * 10000);
int gcd = gcd(whole, 10000);
result.append(" " + (whole/gcd) + "/" + 10000/gcd + " ");
return result.toString();
}
为了解决这个问题(在我的项目之一),我采取了以下措施:
- 内置的十进制/部分字符串的字典。
- 写了一个函数,根据数字的“十进制”部分和匹配条件搜索字典中最接近的匹配分数。
org.apache.commons.math怎么样?他们有一个分数类,需要一个双。
http://commons.apache.org/math/api-1.2/org/apache/commons/math/fraction/Fraction.html
你应该能够扩展它,并给它的功能为第64。你也可以添加一个toString,它可以很容易地打印出你的分数的整个数字部分。
分数(双精度值,整数 maxDenominator)创建给定的双值和最大 分母的分数 。
正如其他几个人已经指出的那样,可以用IEEE浮点数来精确地表示64的小数部分。这意味着我们也可以通过移动和屏蔽位来转换成分数。
这里不是解释浮点表示的所有细节的地方,详情请参考wikipedia。
简而言之:浮点数存储为(sign)(exp)(frac)其中sign是1位,exp是11位,frac是小数部分(在1之后)并且是52位。这是enterpreted的数量:
(sign == 1 ? -1 : 1) * 1.(frac) * 2^(exp-1023)
因此,我们可以通过点accoring移动到指数和点后屏蔽掉6位获得第64。在Java:
private static final long MANTISSA_FRAC_BITMAP = 0xfffffffffffffl;
private static final long MANTISSA_IMPLICIT_PREFIX = 0x10000000000000l;
private static final long DENOM_BITMAP = 0x3f; // 1/64
private static final long DENOM_LEN = 6;
private static final int FRAC_LEN = 52;
public String floatAsFrac64(double d) {
long bitmap = Double.doubleToLongBits(d);
long mantissa = bitmap & MANTISSA_FRAC_BITMAP | MANTISSA_IMPLICIT_PREFIX;
long exponent = ((bitmap >> FRAC_LEN) & 0x7ff) - 1023;
boolean negative = (bitmap & (1l << 63)) > 0;
// algorithm:
// d is stored as SE(11)F(52), implicit "1." before F
// move point to the right <exponent> bits to the right:
if(exponent > FRAC_LEN) System.out.println("warning: loosing precision, too high exponent");
int pointPlace = FRAC_LEN-(int)exponent;
// get the whole part as the number left of the point:
long whole = mantissa >> pointPlace;
// get the frac part as the 6 first bits right of the point:
long frac = (mantissa >> (pointPlace-DENOM_LEN)) & DENOM_BITMAP;
// if the last operation shifted 1s out to the right, we lost precision, check with
// if any of these bits are set:
if((mantissa & ((MANTISSA_FRAC_BITMAP | MANTISSA_IMPLICIT_PREFIX) >> (pointPlace - DENOM_LEN))) > 0) {
System.out.println("warning: precision of input is smaller than 1/64");
}
if(frac == 0) return String.format("%d", whole);
int denom = 64;
// test last bit, divide nom and demon by 1 if not 1
while((frac & 1) == 0) {
frac = frac >> 1;
denom = denom >> 1;
}
return String.format("%d %d/%d", whole, frac, denom);
}
(此代码大概可以缩短,但看完位翻盖这样的代码就足够了,因为它是硬...)
我写了这为我的项目,我希望它可能是有用的:
//How to "Convert" double to fraction("a/b") - [email protected]
private boolean isInt(double number){
if(number%2==0 ||(number+1)%2==0){
return true;
}
return false;
}
private String doubleToFraction(double doub){
//we get the whole part
int whole = (int)doub;
//we get the rest
double rest = doub - (double)whole;
int numerator=1,denominator=1;
//if the whole part of the number is greater than 0
//we'll try to transform the rest of the number to an Integer
//by multiplying the number until it become an integer
if(whole >=1){
for(int i = 2; ; i++){
/*when we find the "Integer" number(it'll be the numerator)
* we also found the denominator(i,which is the number that transforms the number to integer)
* For example if we have the number = 2.5 when it is multiplied by 2
* now it's 5 and it's integer, now we have the numerator(the number (2.5)*i(2) = 5)
* and the denominator i = 2
*/
if(isInt(rest*(double)i)){
numerator = (int)(rest*(double)i);
denominator = i;
break;
}
if(i>10000){
//if i is greater than 10000 it's posible that the number is irrational
//and it can't be represented as a fractional number
return doub+"";
}
}
//if we have the number 3.5 the whole part is 3 then we have the rest represented in fraction 0.5 = 1/2
//so we have a mixed fraction 3+1/2 = 7/2
numerator = (whole*denominator)+numerator;
}else{
//If not we'll try to transform the original number to an integer
//with the same process
for(int i = 2; ; i++){
if(isInt(doub*(double)i)){
numerator = (int)(doub*(double)i);
denominator = i;
break;
}
if(i>10000){
return doub+"";
}
}
}
return numerator+"/"+denominator;
}
我创建了简单的Fraction库。
库,请访问:https://github.com/adamjak/Fractions
例子:
String s = "1.125";
Fraction f1 = Fraction.tryParse(s);
f1.toString(); // return 9/8
Double d = 2.58;
Fraction f2 = Fraction.createFraction(d);
f2.divide(f1).toString() // return 172/75 (2.29)
- 1. 格式重复小数作为分数
- 2. 双格式为String
- 3. 双数据格式
- 4. 格式双无小数点
- 5. 格式化双向百分比WPF
- 6. 按分组工作,将数据分组为字符串格式
- 7. 如何将双数转换为适合表示英寸的格式的分数?
- 8. JTable双格式化
- 9. 格式化双dp
- 10. 格式双在c#
- 11. JAVA双为字符串格式
- 12. 数组格式作为参数angularjs
- 13. Java - toString格式(格式化双精度)
- 14. 格式作为百分比在数据行上
- 15. 将零填充为单个数字以分格式制作
- 16. SQL中的数据格式(将分钟转换为HH:MM格式)
- 17. 双特定格式和两位小数
- 18. 使用DecimalFormat格式化双数
- 19. 以双数字格式显示日期
- 20. 无法将数字从文件转换为双格式
- 21. 作为两个双打总和的双双精度浮点数
- 22. TSQL格式为百分比
- 23. 将字符串值从服务器格式化为双格式转换为
- 24. 字符串格式作为参数?
- 25. 格式化整数x.xxxxx作为xx.xxx
- 26. 作为格式化时间(分钟)的分钟绘图
- 27. 如何格式化多维数组作为给定的格式
- 28. 错误格式化双打
- 29. printf的双格式问题
- 30. scanf格式警告双重
数据进来好(总是在一英寸的64ths) – Milhous 2008-12-18 20:51:53