ধরা যাক আমাদের 0.33 আছে, আমাদের "1/3" আউটপুট করতে হবে। আমাদের যদি "0.4" থাকে তবে আমাদের "2/5" আউটপুট নিতে হবে।
এটি সাধারণ ক্ষেত্রে ভুল, কারণ 1/3 = 0.3333333 = 0 (3) তদতিরিক্ত, প্রস্তাবিত উপরের সমাধানগুলি থেকে দশমিককে সংজ্ঞায়িত নির্ভুলতার সাথে ভগ্নাংশে রূপান্তর করা যায়, কারণ আউটপুট সবসময় ভগ্নাংশ হয়।
তবে, আমি সূত্রের ভিত্তিতে, অসীম জ্যামিতিক সিরিজের ধারণার ভিত্তিতে অনেকগুলি বিকল্পের সাথে আমার বিস্তৃত ফাংশনটির পরামর্শ দিচ্ছি :
প্রথমে এই ফাংশনটি স্ট্রিং প্রতিনিধিত্বতে ভগ্নাংশের সময়সীমার সন্ধান করার চেষ্টা করছে। তারপরে বর্ণিত উপরের সূত্রটি প্রয়োগ করা হবে।
যুক্তিযুক্ত নম্বর কোডটি সি # তে স্টিফেন এম ম্যাককেমি যুক্তিযুক্ত সংখ্যা বাস্তবায়নের কাছ থেকে নেওয়া হয়েছে । আমি আশা করি অন্য কোডগুলিতে আমার কোডটি পোর্ট করা খুব কঠিন নয়।
/// <summary>
/// Convert decimal to fraction
/// </summary>
/// <param name="value">decimal value to convert</param>
/// <param name="result">result fraction if conversation is succsess</param>
/// <param name="decimalPlaces">precision of considereation frac part of value</param>
/// <param name="trimZeroes">trim zeroes on the right part of the value or not</param>
/// <param name="minPeriodRepeat">minimum period repeating</param>
/// <param name="digitsForReal">precision for determination value to real if period has not been founded</param>
/// <returns></returns>
public static bool FromDecimal(decimal value, out Rational<T> result,
int decimalPlaces = 28, bool trimZeroes = false, decimal minPeriodRepeat = 2, int digitsForReal = 9)
{
var valueStr = value.ToString("0.0000000000000000000000000000", CultureInfo.InvariantCulture);
var strs = valueStr.Split('.');
long intPart = long.Parse(strs[0]);
string fracPartTrimEnd = strs[1].TrimEnd(new char[] { '0' });
string fracPart;
if (trimZeroes)
{
fracPart = fracPartTrimEnd;
decimalPlaces = Math.Min(decimalPlaces, fracPart.Length);
}
else
fracPart = strs[1];
result = new Rational<T>();
try
{
string periodPart;
bool periodFound = false;
int i;
for (i = 0; i < fracPart.Length; i++)
{
if (fracPart[i] == '0' && i != 0)
continue;
for (int j = i + 1; j < fracPart.Length; j++)
{
periodPart = fracPart.Substring(i, j - i);
periodFound = true;
decimal periodRepeat = 1;
decimal periodStep = 1.0m / periodPart.Length;
var upperBound = Math.Min(fracPart.Length, decimalPlaces);
int k;
for (k = i + periodPart.Length; k < upperBound; k += 1)
{
if (periodPart[(k - i) % periodPart.Length] != fracPart[k])
{
periodFound = false;
break;
}
periodRepeat += periodStep;
}
if (!periodFound && upperBound - k <= periodPart.Length && periodPart[(upperBound - i) % periodPart.Length] > '5')
{
var ind = (k - i) % periodPart.Length;
var regroupedPeriod = (periodPart.Substring(ind) + periodPart.Remove(ind)).Substring(0, upperBound - k);
ulong periodTailPlusOne = ulong.Parse(regroupedPeriod) + 1;
ulong fracTail = ulong.Parse(fracPart.Substring(k, regroupedPeriod.Length));
if (periodTailPlusOne == fracTail)
periodFound = true;
}
if (periodFound && periodRepeat >= minPeriodRepeat)
{
result = FromDecimal(strs[0], fracPart.Substring(0, i), periodPart);
break;
}
else
periodFound = false;
}
if (periodFound)
break;
}
if (!periodFound)
{
if (fracPartTrimEnd.Length >= digitsForReal)
return false;
else
{
result = new Rational<T>(long.Parse(strs[0]), 1, false);
if (fracPartTrimEnd.Length != 0)
result = new Rational<T>(ulong.Parse(fracPartTrimEnd), TenInPower(fracPartTrimEnd.Length));
return true;
}
}
return true;
}
catch
{
return false;
}
}
public static Rational<T> FromDecimal(string intPart, string fracPart, string periodPart)
{
Rational<T> firstFracPart;
if (fracPart != null && fracPart.Length != 0)
{
ulong denominator = TenInPower(fracPart.Length);
firstFracPart = new Rational<T>(ulong.Parse(fracPart), denominator);
}
else
firstFracPart = new Rational<T>(0, 1, false);
Rational<T> secondFracPart;
if (periodPart != null && periodPart.Length != 0)
secondFracPart =
new Rational<T>(ulong.Parse(periodPart), TenInPower(fracPart.Length)) *
new Rational<T>(1, Nines((ulong)periodPart.Length), false);
else
secondFracPart = new Rational<T>(0, 1, false);
var result = firstFracPart + secondFracPart;
if (intPart != null && intPart.Length != 0)
{
long intPartLong = long.Parse(intPart);
result = new Rational<T>(intPartLong, 1, false) + (intPartLong == 0 ? 1 : Math.Sign(intPartLong)) * result;
}
return result;
}
private static ulong TenInPower(int power)
{
ulong result = 1;
for (int l = 0; l < power; l++)
result *= 10;
return result;
}
private static decimal TenInNegPower(int power)
{
decimal result = 1;
for (int l = 0; l > power; l--)
result /= 10.0m;
return result;
}
private static ulong Nines(ulong power)
{
ulong result = 9;
if (power >= 0)
for (ulong l = 0; l < power - 1; l++)
result = result * 10 + 9;
return result;
}
ব্যবহারের কয়েকটি উদাহরণ রয়েছে:
Rational<long>.FromDecimal(0.33333333m, out r, 8, false);
// then r == 1 / 3;
Rational<long>.FromDecimal(0.33333333m, out r, 9, false);
// then r == 33333333 / 100000000;
ডান অংশ শূন্য অংশ ছাঁটাই আপনার ক্ষেত্রে:
Rational<long>.FromDecimal(0.33m, out r, 28, true);
// then r == 1 / 3;
Rational<long>.FromDecimal(0.33m, out r, 28, true);
// then r == 33 / 100;
ন্যূনতম পিরিয়ড ডিমেস্ট্রেশন:
Rational<long>.FromDecimal(0.123412m, out r, 28, true, 1.5m));
// then r == 1234 / 9999;
Rational<long>.FromDecimal(0.123412m, out r, 28, true, 1.6m));
// then r == 123412 / 1000000; because of minimu repeating of period is 0.1234123 in this case.
শেষে গোলাকার:
Rational<long>.FromDecimal(0.8888888888888888888888888889m, out r));
// then r == 8 == 9;
সবচেয়ে আকর্ষণীয় কেস:
Rational<long>.FromDecimal(0.12345678m, out r, 28, true, 2, 9);
// then r == 12345678 / 100000000;
Rational<long>.FromDecimal(0.12345678m, out r, 28, true, 2, 8);
// Conversation failed, because of period has not been founded and there are too many digits in fraction part of input value.
Rational<long>.FromDecimal(0.12121212121212121m, out r, 28, true, 2, 9));
// then r == 4 / 33; Despite of too many digits in input value, period has been founded. Thus it's possible to convert value to fraction.
অন্যান্য পরীক্ষা এবং কোড প্রত্যেকে গিথুবের আমার ম্যাথফিউশন লাইব্রেরিতে খুঁজে পেতে পারে ।
.33
=>"1/3"
উদাহরণস্বরূপ উদ্বেগ আমাকে; আমি আশা.33
=>"33/100"
। আমি.33...
অবশ্যই আপনাকে অবশ্যই বোঝাতে চাইছি , তবে এটি একটি সমস্যাটি উদ্ঘাটিত করে - আমরা একটি অ্যালগরিদমে স্থির হওয়ার আগে আমাদের প্রত্যাশিত আচরণের বিষয়ে সিদ্ধান্ত নেওয়া উচিত। @ দেবিলস্কির পাইথন উত্তরটি ব্যবহার করে.limit_denominator()
যা 10 ^ 7 এর সর্বাধিক ডোনোমিনেটরের ডিফল্ট হয়; সম্ভবত অনুশীলন একটি ভাল ডিফল্ট, কিন্তু এই এখনও বাগ পরিচয় করিয়ে দিতে পারেন যদি আপনি সতর্ক থাকুন না হন, এবং না প্রত্যাবর্তন"33/100"
মধ্যে.33
কেস।