বৃত্তাকার () সি ++ এ ভাসানোর জন্য


232

আমার একটি সাধারণ ভাসমান পয়েন্টের বৃত্তাকার ফাংশন প্রয়োজন, এভাবে:

double round(double);

round(0.1) = 0
round(-0.1) = 0
round(-0.9) = -1

আমি খুঁজে পেতে ceil()এবং floor()গণিতে h খুঁজে পেতে পারেন - কিন্তু না round()

এটি স্ট্যান্ডার্ড সি ++ লাইব্রেরিতে অন্য নামের অধীনে উপস্থিত রয়েছে, না এটি অনুপস্থিত ??


1
আপনি যদি কেবল গোলটি নম্বর হিসাবে সংখ্যাটি আউটপুট করতে চান তবে মনে হয় আপনি ঠিক করতে পারেন std::cout << std::fixed << std::setprecision(0) << -0.9, উদাহরণস্বরূপ।
ফ্রাঙ্ক

43
এটি রক্ষা করা হচ্ছে ... উজ্জ্বল নতুন রাউন্ডিং স্কিম সহ নতুন ব্যবহারকারীদের প্রথমে বিদ্যমান উত্তরগুলি পড়তে হবে।
শোগ 9

12
roundসি ++ 11-এর পরে উপলব্ধ <cmath>। দুর্ভাগ্যবশত আপনি Microsoft ভিসুয়াল স্টুডিও রয়েছে এটি এখনও হারিয়েছে: connect.microsoft.com/VisualStudio/feedback/details/775474/...
আলেসান্দ্রো Jacopson

3
আমার উত্তরে আমি যেমন নোট করেছি, নিজের ঘূর্ণায়মানটিতে roundপ্রচুর পরিমাণে সতর্কতা রয়েছে। সি ++ 11 এর আগে, স্ট্যান্ডার্ডটি C90 এর উপর নির্ভর করেছিল যা অন্তর্ভুক্ত নয় round। সি ++ 11 সি 99 এর উপর নির্ভর করে যা রয়েছে তবে এটিতে roundআমি যেমন উল্লেখ করেছি যে এর মধ্যে truncরয়েছে বিভিন্ন বৈশিষ্ট্য এবং প্রয়োগের উপর নির্ভর করে আরও উপযুক্ত হতে পারে। বেশিরভাগ উত্তরগুলি এড়িয়ে যায় বলে মনে হয় যে কোনও ব্যবহারকারী কোনও ইন্টিগ্রাল টাইপ ফেরত দিতে চাইতে পারে যা আরও বেশি সমস্যা রয়েছে।
শফিক ইয়াঘমোর

2
@Uvts_cvs এটি ভিজ্যুয়াল স্টুডিওর সর্বশেষতম সংস্করণে কোনও সমস্যা বলে মনে হচ্ছে না, এটি সরাসরি দেখুন
শফিক ইয়াঘমোর

উত্তর:


144

সি ++ 98 স্ট্যান্ডার্ড লাইব্রেরিতে কোনও রাউন্ড নেই ()। আপনি নিজে একটি লিখতে পারেন যদিও। নিম্নলিখিতটি রাউন্ড হাফ-আপের একটি বাস্তবায়ন :

double round(double d)
{
  return floor(d + 0.5);
}

সি ++ 98 স্ট্যান্ডার্ড লাইব্রেরিতে কোনও গোলাকার কার্যকারিতা না থাকার সম্ভাব্য কারণ হ'ল এটি বাস্তবে বিভিন্ন উপায়ে প্রয়োগ করা যেতে পারে। উপরেরটি একটি সাধারণ উপায় তবে রাউন্ড-টু- ইভেনের মতো আরও কিছু রয়েছে যা আপনি প্রচুর রাউন্ডিং করতে যাচ্ছেন যদি তা কম পক্ষপাতদুষ্ট এবং সাধারণত ভাল; যদিও এটি প্রয়োগ করা কিছুটা জটিল।


53
এটি সঠিকভাবে নেতিবাচক সংখ্যাগুলি পরিচালনা করে না। লিটব দ্বারা উত্তর সঠিক।
নিবন্ধিত ব্যবহারকারী

39
@ আন্তজারজয়িন: হ্যাঁ, এটি লিটবের উত্তরের জন্য নেতিবাচক সংখ্যাগুলি আলাদাভাবে পরিচালনা করে তবে এটি "ভুল" করে না।
রডি

39
ছাঁটাইয়ের আগে 0.5 যোগ করা বিবিধ ইনপুটগুলির নিকটতম পূর্ণসংখ্যার সাথে 0.49999999999999994 সহ ব্যর্থ হয়। ব্লগ.ফ্রেমা-c.com/index.php?post/2013/05/02/nearbyintf1
পাস্কেল কুয়াক

10
@ সেরগি0: কোনও "সঠিক" এবং "ভুল" নেই কারণ গোল করার একাধিক সংজ্ঞা রয়েছে যা অর্ধপথের স্থানে কী ঘটে তা স্থির করে। রায় দেওয়ার আগে আপনার সত্যতা যাচাই করুন।
জন

16
@ মুহাম্মাদআন্নাকীব: আপনি ঠিক বলেছেন, সি ++ ১১ প্রকাশের পর থেকে বিষয়গুলির ব্যাপক উন্নতি হয়েছে। এই প্রশ্নটি জিজ্ঞাসা করা হয়েছিল এবং অন্য সময়ে উত্তর দেওয়া হয়েছিল যখন জীবন ছিল কঠিন এবং আনন্দ কম ছিল। এটি সেই সময়ের বীরদের যারা এখনও বেঁচে ছিল এবং লড়াই করেছিল এবং যারা দরিদ্র প্রাণীরা এখনও আধুনিক সরঞ্জামগুলি ব্যবহার করতে অক্ষম তাদের পক্ষে এটি একটি অবিচ্ছিন্ন হিসাবে রয়ে গেছে।
Andreas Magnusson

96

বুস্ট রাউন্ডিং ফাংশনগুলির একটি সহজ সেট সরবরাহ করে।

#include <boost/math/special_functions/round.hpp>

double a = boost::math::round(1.5); // Yields 2.0
int b = boost::math::iround(1.5); // Yields 2 as an integer

আরও তথ্যের জন্য, বুস্ট ডকুমেন্টেশন দেখুন

সম্পাদনা : যেহেতু সি ++ 11, আছে std::round, std::lroundএবংstd::llround


2
আমি ইতিমধ্যে আমার প্রকল্পে বুস্ট ব্যবহার করছিলাম, এটির জন্য +1, নির্বোধের floor(value + 0.5)পদ্ধতির ব্যবহারের চেয়ে অনেক ভাল !
গুস্তাভো ম্যাকিয়েল

@ গুস্তাভোম্যাসিল আমি জানি আমি গেমটি থেকে কিছুটা দেরি করেছি, তবে বাস্তবায়ন বাড়িয়ে তোলা হয়েছে floor(value + 0.5)
এন। 'সর্বনাম' মি।

এটি আসলে না: github.com/boostorg/math/blob/develop/incolve/boost/math/… 4 বছর পরে, আমি এও বলতে চাই floor(value + 0.5)না যে এটি মোটেও নিষ্পাপ নয়, বরং প্রসঙ্গ এবং প্রকৃতির উপর নির্ভর করে আপনি গোল করতে চান মান!
গুস্তাভো ম্যাকিয়েল

84

সি ++ 03 স্ট্যান্ডার্ডটি স্ট্যান্ডার্ড সি লাইব্রেরিটির জন্য সি 90 স্ট্যান্ডার্ডের উপর নির্ভর করে যা সি ++ 03 স্টাডেন্টের আচ্ছাদিত (সি ++3 এর নিকটতম প্রকাশ্যে উপলব্ধ খসড়া স্ট্যান্ডার্ডটি এন 1804 ) বিভাগের 1.2 আদর্শ রেফারেন্স :

আইএসও / আইসিসি 9899: 1990 এর ধারা 7 এবং আইএসও / আইসিসি 9899 / এমডি 1: 1995 এর ধারা 7 এ বর্ণিত গ্রন্থাগারটির পরবর্তীকালে স্ট্যান্ডার্ড সি লাইব্রেরি নামে পরিচিত। 1)

আমরা যদি সিপ্রেফারেন্সের উপর রাউন্ড, লাউন্ড, ললাউন্ডের জন্য সি ডকুমেন্টেশনে যাই আমরা দেখতে পারি যে বৃত্তাকার এবং সম্পর্কিত ফাংশনগুলি C99 এর অংশ এবং সুতরাং সি ++ 03 বা তার আগে পাওয়া যাবে না।

সি ++ ১১-এ এই পরিবর্তনগুলি যেহেতু সি ++ 11 সি স্ট্যান্ডার্ড লাইব্রেরির জন্য সি 99 খসড়া স্ট্যান্ডার্ডের উপর নির্ভর করে এবং তাই স্ট্যান্ড :: গোল করে এবং অবিচ্ছেদ্য ফেরতের প্রকারের জন্য স্ট্যান্ড :: লাউন্ড, স্ট্যান্ড :: লাউন্ড :

#include <iostream>
#include <cmath>

int main()
{
    std::cout << std::round( 0.4 ) << " " << std::lround( 0.4 ) << " " << std::llround( 0.4 ) << std::endl ;
    std::cout << std::round( 0.5 ) << " " << std::lround( 0.5 ) << " " << std::llround( 0.5 ) << std::endl ;
    std::cout << std::round( 0.6 ) << " " << std::lround( 0.6 ) << " " << std::llround( 0.6 ) << std::endl ;
}

সি 99 এর থেকে অন্য বিকল্পটি হবে স্ট্যান্ড :: ট্রাঙ্ক যা:

আর্গুমেন্টের চেয়ে নিকটতম পূর্ণসংখ্যার পরিমাপ বৃহত্তর নয়।

#include <iostream>
#include <cmath>

int main()
{
    std::cout << std::trunc( 0.4 ) << std::endl ;
    std::cout << std::trunc( 0.9 ) << std::endl ;
    std::cout << std::trunc( 1.1 ) << std::endl ;

}

আপনার যদি নন সি ++ ১১ টি অ্যাপ্লিকেশন সমর্থন করতে হয় তবে আপনার সেরা বাজি হ'ল বুস্ট রাউন্ড, বেহাল, লাউন্ড, লাউন্ডাউন্ড বা বুস্ট ট্রাঙ্ক ব্যবহার করা

আপনার নিজের সংস্করণটি বৃত্তাকারে ঘূর্ণন করা শক্ত

নিজের ঘূর্ণায়মান সম্ভবত এটির চেয়ে কঠোর প্রচেষ্টাটির মতো নয়: নিকটতম পূর্ণসংখ্যার দিকে গোলাকার ভাসা, অংশ 1 , নিকটতম পূর্ণসংখ্যার কাছে রাউন্ডিং ফ্লোট, অংশ 2 এবং নিকটতম পূর্ণসংখ্যার কাছে রাউন্ডিং ফ্লোট, অংশ 3 ব্যাখ্যা করুন:

উদাহরণস্বরূপ একটি সাধারণ রোল আপনার প্রয়োগটি ব্যবহার করে std::floor যুক্ত করা 0.5সমস্ত ইনপুটগুলিতে কাজ করে না:

double myround(double d)
{
  return std::floor(d + 0.5);
}

এটির জন্য একটি ইনপুট ব্যর্থ হবে 0.49999999999999994এটির , ( এটি সরাসরি দেখুন )।

আর একটি সাধারণ বাস্তবায়নের মধ্যে একটি অবিচ্ছেদ্য প্রকারে ভাসমান পয়েন্ট টাইপ করা জড়িত, যা অবিচ্ছেদ্য অংশটিকে গন্তব্য প্রকারের মধ্যে প্রতিনিধিত্ব করা যায় না এমন ক্ষেত্রে অনির্ধারিত আচরণের আবেদন করতে পারে। আমরা এটি খসড়া সি ++ স্ট্যান্ডার্ড বিভাগ থেকে ভাসমান-ইন্টিগ্রাল রূপান্তরগুলি থেকে দেখতে পারি4.9 যা ( জোর আমার ):

ভাসমান বিন্দু প্রকারের একটি অগ্রগতি পূর্ণসংখ্যার প্রকারে রূপান্তরিত হতে পারে। রূপান্তর কাটা; অর্থাৎ, ভগ্নাংশ অংশ বাতিল করা হয়।যদি কাটা মানটি গন্তব্যের ধরণে প্রতিনিধিত্ব না করা যায় তবে আচরণটি অপরিজ্ঞাত। [...]

উদাহরণ স্বরূপ:

float myround(float f)
{
  return static_cast<float>( static_cast<unsigned int>( f ) ) ;
}

প্রদত্ত std::numeric_limits<unsigned int>::max()হল4294967295 নিম্নলিখিত কল:

myround( 4294967296.5f ) 

উপচে পড়বে, এটি সরাসরি দেখুন )।

আমরা দেখতে পাচ্ছি যে সি তে বৃত্তাকার () বাস্তবায়নের সংক্ষিপ্ত উপায়টির উত্তরটি দেখে এটি সত্যই কতটা কঠিন ? যা newlibs রেফারেন্সিং একক নির্ভুলতা ভাসমান রাউন্ডের সংস্করণ । এটি সহজ মনে হয় এমন কোনও কিছুর জন্য খুব দীর্ঘ ফাংশন। এটি অসম্ভব বলে মনে হচ্ছে যে ভাসমান পয়েন্ট বাস্তবায়নের অন্তরঙ্গ জ্ঞান ছাড়াই যে কেউ এই ফাংশনটি সঠিকভাবে প্রয়োগ করতে পারে:

float roundf(x)
{
  int signbit;
  __uint32_t w;
  /* Most significant word, least significant word. */
  int exponent_less_127;

  GET_FLOAT_WORD(w, x);

  /* Extract sign bit. */
  signbit = w & 0x80000000;

  /* Extract exponent field. */
  exponent_less_127 = (int)((w & 0x7f800000) >> 23) - 127;

  if (exponent_less_127 < 23)
    {
      if (exponent_less_127 < 0)
        {
          w &= 0x80000000;
          if (exponent_less_127 == -1)
            /* Result is +1.0 or -1.0. */
            w |= ((__uint32_t)127 << 23);
        }
      else
        {
          unsigned int exponent_mask = 0x007fffff >> exponent_less_127;
          if ((w & exponent_mask) == 0)
            /* x has an integral value. */
            return x;

          w += 0x00400000 >> exponent_less_127;
          w &= ~exponent_mask;
        }
    }
  else
    {
      if (exponent_less_127 == 128)
        /* x is NaN or infinite. */
        return x + x;
      else
        return x;
    }
  SET_FLOAT_WORD(x, w);
  return x;
}

অন্যদিকে যদি অন্য কোনও সমাধানের ব্যবহারযোগ্য না হয় তবে এটি সম্ভাব্যভাবে একটি বিকল্প হতে পারে কারণ এটি একটি ভাল পরীক্ষামূলক বাস্তবায়ন।


5
@ ডাউনভোটার দয়া করে ব্যাখ্যা করুন কী কী উন্নতি করা যায়? এখানে উত্তরটির বেশিরভাগ অংশই ঠিক ভুল, কারণ তারা তাদের নিজস্ব বৃত্তাকারটি রোল করার চেষ্টা করে যা সমস্তই একরকম বা অন্য কোনওভাবে ব্যর্থ হয়। আমার ব্যাখ্যাতে যদি কিছু অনুপস্থিত থাকে তবে দয়া করে আমাকে জানান।
শফিক ইয়াঘমোর

1
দুর্দান্ত সম্পূর্ণ উত্তর - বিশেষত ঠিক 0.5 অংশের নীচে। আরেকটি কুলুঙ্গি: round(-0.0)। সি স্পেস নির্দিষ্ট করে উপস্থিত হয় না। আমি -0.0ফলাফল হিসাবে আশা করব ।
chux - মনিকা পুনরায় ইনস্টল করুন

3
@ chux আকর্ষণীয় এবং আইইইই 754-2008 স্ট্যান্ডার্ড নির্দিষ্ট করে যে রাউন্ডিংটি শূন্য এবং অসীমের লক্ষণগুলি সংরক্ষণ করে (দেখুন 5.9)।
রুস্লান

1
@ শাফিক এটি দুর্দান্ত উত্তর is আমি কখনও ভাবিনি যে এমনকি রাউন্ডিংও একটি তুচ্ছ তাত্পর্যপূর্ণ কাজ।
রুস্লান

1
সম্ভবত উল্লেখযোগ্য যে সীমাবদ্ধ এবং পারফরম্যান্স কারণে সি ++ 11 উপলভ্য যখন std::rint()প্রায়শই std::round()পছন্দ হয়। এটির round()বিশেষ মোডের বিপরীতে বর্তমান রাউন্ডিং মোডটি ব্যবহার করে । এটি x86 এর ক্ষেত্রে আরও কার্যকর হতে পারে, যেখানে rintএকক নির্দেশের সাথে ইনলাইন করতে পারে। ( -ffast-math জিসিসি এবং ক্ল্যাং এগুলি গডবোল্ট.আর্গ / জি / ৫ ইউএসএল 2 ছাড়াই করে , কেবল ঝনঝনাই প্রায় সমতুল্যকে ইনলাইন করে nearbyint()) এআরএমের একক-নির্দেশনা সমর্থন রয়েছে round()তবে x86 এ এটি একাধিক নির্দেশাবলীর সাথে কেবল ইনলাইন করতে পারে, এবং কেবলমাত্র-ffast-math
পিটার কর্ডেসের সাথে

71

এটি লক্ষণীয় যে আপনি যদি রাউন্ডিংয়ের মধ্য দিয়ে কোনও পূর্ণসংখ্যার ফলাফল চান তবে আপনার এটি সিল বা তল দিয়ে কোনও পাস করার দরকার নেই। অর্থাত,

int round_int( double r ) {
    return (r > 0.0) ? (r + 0.5) : (r - 0.5); 
}

3
0.499999999999999994 এর জন্য প্রত্যাশিত ফলাফল দেয় না যদিও (ভাল, আপনি অবশ্যই যা আশা করেন তার উপর নির্ভর করে তবে 0 আমার চেয়ে 1 টির চেয়ে বেশি যুক্তিসঙ্গত বলে মনে হয়)
স্টেজ

পছন্দ করেছেন আমি দেখতে পেয়েছি যে আমার ধ্রুবকগুলিতে দীর্ঘ ডাবল আক্ষরিক প্রত্যয় যুক্ত করা আপনার উদাহরণের সমস্যার সমাধান করেছে, তবে অন্যান্য নির্ভুল উদাহরণ রয়েছে যা এটি গ্রহণ করবে না তা আমি জানি না।
ক্যালাক্সি

1
বিটিডব্লু আপনি যদি 0.5 এর পরিবর্তে 0.49999999999999994 যোগ করেন তবে ইনপুট হিসাবে 0.4999999999999999994 এবং 500000000000000001.0 উভয়ের জন্য ঠিক আছে। যদিও এটি সমস্ত মানগুলির জন্য ঠিক আছে কিনা তা নিশ্চিত নই এবং আমি এটিই চূড়ান্ত সমাধান বলে উল্লেখ করে কোনও রেফারেন্স পাইনি।
স্টিজ

1
@ স্টিজন সকল মানগুলির জন্য ঠিক আছে, যদি আপনি দু'টি পূর্ণসংখ্যার মধ্যবর্তী মানের মধ্যে সঠিক দিকটি গোল না করে সেদিকে খেয়াল রাখেন না। চিন্তা না করেই আমি নিম্নলিখিত কেসগুলির সাথে কেস বিশ্লেষণ করে প্রমাণ করব: 0 <= d <0.5, 0.5 <= d <1.5, 1.5 <= d <2 ^ 52, d> = 2 ^ 52। আমি একক নির্ভুলতার কেসটিও নিখুঁতভাবে পরীক্ষা করেছি।
পাস্কেল কুয়াক

3
প্রতি ৪.৯ [কনভেন্টফিন্ট], "যদি কাটা মানটিকে গন্তব্যের ধরণে প্রতিনিধিত্ব করা না যায় তবে আচরণটি অপরিজ্ঞাত ।" সুতরাং এটি কিছুটা বিপজ্জনক। অন্যান্য এসও উত্তরগুলি কীভাবে এটি দৃust়ভাবে করা যায় তা বর্ণনা করে।
টনি ডেলরয়

41

Cmath এ সি ++ 11 সাল থেকে এটি উপলব্ধ ( http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf অনুসারে )

#include <cmath>
#include <iostream>

int main(int argc, char** argv) {
  std::cout << "round(0.5):\t" << round(0.5) << std::endl;
  std::cout << "round(-0.5):\t" << round(-0.5) << std::endl;
  std::cout << "round(1.4):\t" << round(1.4) << std::endl;
  std::cout << "round(-1.4):\t" << round(-1.4) << std::endl;
  std::cout << "round(1.6):\t" << round(1.6) << std::endl;
  std::cout << "round(-1.6):\t" << round(-1.6) << std::endl;
  return 0;
}

আউটপুট:

round(0.5):  1
round(-0.5): -1
round(1.4):  1
round(-1.4): -1
round(1.6):  2
round(-1.6): -2

1
এছাড়াও রয়েছে lroundএবং llroundঅবিচ্ছেদ্য ফলাফলের জন্য
sp2danny

@ sp2danny: বা আরও ভাল, জিরো টাইব্রেক-এর থেকে দূরে এর মজাদার পরিবর্তে lrintবর্তমান রাউন্ডিং মোডটি ব্যবহার করতেround
পিটার কর্ডেস

27

এটি সাধারণত হিসাবে প্রয়োগ করা হয় floor(value + 0.5)

সম্পাদনা করুন: এবং এটি সম্ভবত গোল না বলা হয় যেহেতু আমি কমপক্ষে তিনটি রাউন্ডিং অ্যালগরিদম জানি: গোল থেকে শূন্য, নিকটতম পূর্ণসংখ্যার বৃত্তাকার এবং ব্যাঙ্কারের গোলাকার। আপনি নিকটতম পূর্ণসংখ্যার জন্য জিজ্ঞাসা করছেন।


1
'রাউন্ড' এর বিভিন্ন সংস্করণের মধ্যে পার্থক্য করা ভাল। কোনটি কখন বেছে নেবে তা জেনে রাখা ভাল।
xtofl

5
প্রকৃতপক্ষে বিভিন্ন বৃত্তাকার অ্যালগরিদম রয়েছে যা সবাই "সঠিক" হওয়ার পক্ষে যুক্তিসঙ্গত দাবি করতে পারে। তবে মেঝে (মান + 0.5) এর মধ্যে একটি নয়। 0.49999997f বা সমমানের দ্বিগুণ হিসাবে কিছু মানের জন্য, উত্তরটি কেবলমাত্র ভুল - এটি ১.০ এ পরিণত হবে যখন সকলেই সম্মত হয় যে এটি শূন্য হওয়া উচিত। বিশদ জন্য এই পোস্টটি দেখুন: blog.frama-c.com/index.php?post/2013/05/02/nearbyintf1
ব্রুস ডসন

14

2 টি সমস্যা রয়েছে যা আমরা দেখছি:

  1. গোলাকার রূপান্তর
  2. রূপান্তর টাইপ করুন।

রাউন্ডিং রূপান্তরগুলির অর্থ গোলাকার ± ভাসমান / নিকটতম মেঝে থেকে সিল ফ্ল্যাট / ডাবল double আপনার সমস্যা এখানেই শেষ হতে পারে। তবে আপনি যদি ইন্ট / লং প্রত্যাবর্তনের প্রত্যাশা করেন তবে আপনার ধরণের রূপান্তর সম্পাদন করা দরকার, এবং এইভাবে "ওভারফ্লো" সমস্যাটি আপনার সমাধানে আসতে পারে। সুতরাং, আপনার কার্যক্রমে ত্রুটির জন্য একটি চেক করুন

long round(double x) {
   assert(x >= LONG_MIN-0.5);
   assert(x <= LONG_MAX+0.5);
   if (x >= 0)
      return (long) (x+0.5);
   return (long) (x-0.5);
}

#define round(x) ((x) < LONG_MIN-0.5 || (x) > LONG_MAX+0.5 ?\
      error() : ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))

থেকে: http://www.cs.tut.fi/~jkorpela/round.html


গণিত সঠিক নাও হওয়ায় জটিলতা ব্যবহার LONG_MIN-0.5এবং LONG_MAX+0.5পরিচয় করিয়ে দেওয়া। সঠিক রূপান্তরকরণের জন্য নির্ভুলতা LONG_MAXঅতিক্রম করতে পারে double। আরও সম্ভবত assert(x < LONG_MAX+0.5); (<বনাম <=) হিসাবে যথাযথ LONG_MAX+0.5উপস্থাপনযোগ্য হতে পারে এবং কাস্ট ব্যর্থ (x)+0.5হওয়ার সঠিক ফলাফল থাকতে পারে LONG_MAX+1want longঅন্যান্য কোণার সমস্যা।
chux - মনিকা

আপনার ফাংশনটি কল করবেন না round(double), ইতিমধ্যে সেই নামটির একটি স্ট্যান্ডার্ড গণিত গ্রন্থাগার ফাংশন রয়েছে (সি ++ 11 এ) তাই এটি বিভ্রান্তিকর। std::lrint(x)এটি উপলব্ধ থাকলে ব্যবহার করুন ।
পিটার কর্ডেস

11

বুস্টে একটি নির্দিষ্ট ধরণের রাউন্ডিংও প্রয়োগ করা হয়:

#include <iostream>

#include <boost/numeric/conversion/converter.hpp>

template<typename T, typename S> T round2(const S& x) {
  typedef boost::numeric::conversion_traits<T, S> Traits;
  typedef boost::numeric::def_overflow_handler OverflowHandler;
  typedef boost::numeric::RoundEven<typename Traits::source_type> Rounder;
  typedef boost::numeric::converter<T, S, Traits, OverflowHandler, Rounder> Converter;
  return Converter::convert(x);
}

int main() {
  std::cout << round2<int, double>(0.1) << ' ' << round2<int, double>(-0.1) << ' ' << round2<int, double>(-0.9) << std::endl;
}

মনে রাখবেন যে আপনি কেবলমাত্র টু-ইন্টিজার রূপান্তরটি করলে এটি কাজ করে।


2
বুস্ট সাধারণ রাউন্ডিং ফাংশনগুলির একটি সেটও সরবরাহ করে; আমার উত্তর দেখুন।
ড্যানিয়েল ওল্ফ

আপনি ব্যবহার করতে পারেন boost:numeric::RoundEven< double >::nearbyint যদি পূর্ণসংখ্যার পছন্দ না করেন আপনি সরাসরি করতে পারেন। @DanielWolf নোট যে সহজ ফাংশন যা aka.nice দ্বারা layed সমস্যা রয়েছে +0,5 ব্যবহার বাস্তবায়িত হয়
stijn

6

আপনি এর সাথে n সংখ্যার যথার্থতার সাথে গোল করতে পারেন:

double round( double x )
{
const double sd = 1000; //for accuracy to 3 decimal places
return int(x*sd + (x<0? -0.5 : 0.5))/sd;
}

4
আপনার
সংকলকটির

আমি মনে করি এটি গ্রহণযোগ্য হবে যখন এটি ব্যবহার করা হবে: আপনার দ্বিগুণ মান যদি 1.0 ই + 19 হয় তবে 3 টি জায়গায় গোল করার অর্থ হবে না।
কার্ল

3
অবশ্যই, তবে প্রশ্নটি জেনেরিক রাউন্ডের জন্য এবং আপনি কীভাবে এটি ব্যবহার করবেন তা নিয়ন্ত্রণ করতে পারবেন না। সিল এবং মেঝে যেখানে অবিশ্বাস্য হওয়ার কোনও কারণ নেই।
ওরফে.নিস

এর ব্যাপ্তির সীমার বাইরে অপরিবর্তিত আচরণ রয়েছে int। (এক্স 86 উপর বাস্তবে, আউট-অফ-পরিসীমা FP মান করা হবে CVTTSD2SIউত্পাদন0x80000000 পূর্ণসংখ্যা বিট প্যাটার্ন, অর্থাত হিসাবে INT_MIN, যা রূপান্তরিত ফিরে আসবে double
পিটার Cordes

5

এই দিনগুলিতে C ++ 11 সংকলক ব্যবহার করতে সমস্যা হওয়া উচিত নয় যা একটি C99 / C ++ 11 গণিত লাইব্রেরি অন্তর্ভুক্ত করে। কিন্তু তারপরে প্রশ্নটি দাঁড়ায়: আপনি কোন রাউন্ডিং ফাংশনটি বেছে নেন?

C99 / C ++ 11 round()প্রায়শই আসলে আপনি চান এমন গোলাকার কার্য নয় । এটি একটি ফানি রাউন্ডিং মোড ব্যবহার করে যা হাফ-ওয়ে ক্ষেত্রে ( +-xxx.5000) ক্ষেত্রে টাই-ব্রেক হিসাবে 0 থেকে দূরে । আপনি যদি বিশেষভাবে সেই রাউন্ডিং মোডটি চান তবে বা আপনি একটি সি ++ বাস্তবায়ন লক্ষ্য করছেন যেখানে এর round()চেয়ে দ্রুতrint() , তবে এটি ব্যবহার করুন (বা এই প্রশ্নের অন্য উত্তরগুলির সাথে এর আচরণ অনুকরণ করুন যা এটি মুখের মূল্য হিসাবে নিয়েছে এবং সাবধানে সেই নির্দিষ্টটি পুনরুত্পাদন করেছে গোলাকার আচরণ।)

round()টাই-ব্রেক হিসাবে এমনকি রাউন্ডিংটি আইইইই 7575৫ ডিফল্ট রাউন্ড থেকে নিকটতম মোডে পৃথক । নিকটতম এমনকি এমনকি সংখ্যার গড় পরিমাপের পরিসংখ্যানমূলক পক্ষপাত এড়ানো হয় তবে সংখ্যার দিকে পক্ষপাতও করে।

দুটি ডিগ্রি গ্রন্থাগার রাউন্ডিং ফাংশন রয়েছে যা বর্তমান ডিফল্ট রাউন্ডিং মোড ব্যবহার করে: std::nearbyint()এবং std::rint()উভয়ই C99 / C ++ 11 এ যুক্ত হয়েছে, তাই যে কোনও সময় উপলব্ধ std::round()। পার্থক্য কেবল এটিইnearbyint কখনই FE_INEXACT উত্থাপন না।

rint()পারফরম্যান্সের কারণে পছন্দ করুন : জিসিসি এবং ঝাঁকুনি উভয়ই এটিকে সহজেই ইনলাইন করে তবে জিসিসি কখনই ইনলাইন হয় না nearbyint()(এমনকি এর সাথেও -ffast-math)


x86-64 এবং AArch64 এর জন্য জিসিসি / বিড়ম্বনা

আমি ম্যাট গডবোল্টের কম্পাইলার এক্সপ্লোরারে কিছু পরীক্ষার ফাংশন রেখেছি , যেখানে আপনি সোর্স + এসএম আউটপুট দেখতে পাবেন (একাধিক সংকলকের জন্য)। সংকলক আউটপুট পড়ার বিষয়ে আরও তথ্যের জন্য এই প্রশ্নোত্তরটি দেখুন এবং ম্যাটস এর সিপিপিসন2017 আলাপ দেখুন: "আমার সংকলক ইদানীং আমার জন্য কী করেছে? সংকলকের idাকনাটি আনবোল্ট করা , "

এফপি কোডে, এটি সাধারণত ছোট ফাংশনগুলিকে ইনলাইন করতে একটি বড় জয়। বিশেষত নন-উইন্ডোজে, যেখানে স্ট্যান্ডার্ড কলিং কনভেনশনটিতে কোনও কল-সংরক্ষিত রেজিস্টার নেই, তাই সংকলকটি এক্সএমএম রেজিস্টারে কোনও এফপি মান রাখতে পারে না একটি জুড়েcall । সুতরাং আপনি যদি সত্যই asm জানেন না, তবুও আপনি সহজেই দেখতে পারবেন এটি লাইব্রেরির ফাংশনটির জন্য কেবল একটি লেজ-কল বা এটি এক বা দুটি গণিতের নির্দেশের সাথে linedুকেছে কিনা easily এক বা দুটি নির্দেশাবলীর সাথে অন্তর্ভুক্ত যে কোনও কিছু ফাংশন কলের চেয়ে ভাল (x86 বা এআরএম-এ এই নির্দিষ্ট কাজের জন্য)।

X86-এ, এসএসই 4.1 এর সাথে মেলে এমন যে কোনও কিছু এসএসই roundsd4.1 roundpd(বা এভিএক্স vroundpd) এর সাথে স্বয়ংক্রিয়ভাবে ভেক্টরাইজ করতে পারে । (এফপি-> পূর্ণসংখ্যার রূপান্তরগুলি প্যাক করা সিমডি ফর্মগুলিতেও পাওয়া যায়, এফপি-> -৪-বিট পূর্ণসংখ্যার জন্য যা AVX512 প্রয়োজন)

  • std::nearbyint():

    • x86 ঝনঝন: একক ইনসনে ইনলাইনস -msse4.1
    • x86 গিসিসি: কেবলমাত্র এক সিসি ইনসনে ইনলাইন করে -msse4.1 -ffast-mathএবং কেবল জিসিসি 5.4 এবং তার আগে । পরে জিসিসি এটি কখনই ইনলাইন করে না (সম্ভবত তারা বুঝতে পারেনি যে তাত্ক্ষণিক বিটগুলির মধ্যে একটিও অক্ষত ব্যতিক্রমকে দমন করতে পারে? এটাই ঝাঁকুনি ব্যবহার করে তবে পুরানো জিসিসি এটি তত্ক্ষণাত্ ব্যবহার করে rintযখন এটি ইনলাইন করে না)
    • AArch64 gcc6.3: ডিফল্টরূপে একটি একক ইনসনে ইনলাইন করে।
  • std::rint:

    • x86 ঝনঝন: একক ইনসনে ইনলাইনস -msse4.1
    • x86 gcc7: এর সাথে একক ইনসনে ইনলাইন -msse4.1। (এসএসই 4.1 ছাড়া বেশ কয়েকটি নির্দেশের সাথে ইনলাইন)
    • x86 gcc6.x এবং তার আগের: একক ইনসনে ইনলাইন -ffast-math -msse4.1
    • AArch64 gcc: ডিফল্টরূপে একটি একক ইনসনে ইনলাইন করে
  • std::round:

    • x86 ঝাঁকুনি: ইনলাইন হয় না
    • x86 জিসিসি: এর সাথে একাধিক নির্দেশনার সাথে ইনলাইন -ffast-math -msse4.1 দুটি ভেক্টর ধ্রুবক প্রয়োজন ।
    • এআরচ g৪ জিসিসি: একটি একক নির্দেশকে ইনলাইন করে (এই রাউন্ডিং মোডের পাশাপাশি আইইইই ডিফল্ট এবং অন্যান্য বেশিরভাগের জন্য এইচডাব্লু সমর্থন))
  • std::floor/ std::ceil/std::trunc

    • x86 ঝনঝন: একক ইনসনে ইনলাইনস -msse4.1
    • x86 gcc7.x: এর সাথে একক ইনসনে ইনলাইন -msse4.1
    • x86 gcc6.x এবং তার আগের: একক ইনসনে ইনলাইন -ffast-math -msse4.1
    • এআরচ g৪ জিসিসি: একক নির্দেশে ডিফল্টরূপে ইনলাইন

বৃত্তাকার int/ long/ long long:

আপনার এখানে দুটি বিকল্প রয়েছে: ব্যবহার করুন lrint(যেমন rintতবে রিটার্ন)long , বা এর long longজন্য llrint), বা একটি এফপি-> এফপি রাউন্ডিং ফাংশন ব্যবহার করুন এবং তারপরে একটি পূর্ণসংখ্যা টাইপকে স্বাভাবিক উপায়ে রূপান্তর করুন (কাটা দিয়ে)। কিছু সংকলক অন্যটির চেয়ে এক উপায়ে আরও ভাল করে।

long l = lrint(x);

int  i = (int)rint(x);

মনে রাখবেন যে int i = lrint(x) রূপান্তর করে floatবা double-> longপ্রথমে এবং তারপরে পূর্ণসংখ্যাকে কাটা হয়int । সীমার বাইরে থাকা পূর্ণসংখ্যার জন্য এটি একটি পার্থক্য তৈরি করে: সি ++ এ অপরিজ্ঞাত আচরণ, তবে x86 এফপি -> অন্তর্নির্দেশ নির্দেশাবলী (যা সংকলক নির্গত হবে যখন সংবিধানের সময় ধ্রুবক প্রচারের সময় UB না দেখে তবেই এটি নির্গত হয়) কোডটি তৈরি করার অনুমতি দেওয়া হয়েছে যা এটি কার্যকর হলে কখনও ভেঙে যায়)।

X86-তে, একটি FP-> পূর্ণসংখ্যার রূপান্তর যা পূর্ণসংখ্যাকে উত্পন্ন করে INT_MINবা LLONG_MIN( 0x8000000কেবলমাত্র সাইন-বিট সেট সহ একটি বিট-প্যাটার্ন বা 64-বিট সমতুল্য)। ইন্টেল এটিকে "পূর্ণসংখ্যা অনির্দিষ্ট" মান বলে। (দেখুনcvttsd2si ম্যানুয়ালি প্রবেশ করানোর , SSE2 নির্দেশ যে ধর্মান্তরিত (ছাঁটাই সঙ্গে) স্বাক্ষরিত পূর্ণসংখ্যা থেকে স্কালে ডবল। এটা দিয়ে উপলব্ধ 32 বিট বা 64 বিট পূর্ণসংখ্যা গন্তব্য (শুধুমাত্র 64-বিট মোডে)। এর রয়েছে একটি cvtsd2si(বর্তমান রাউন্ডইং সাথে রূপান্তর মোড), যা আমরা সংকলকটি নির্গত করতে চাই, তবে দুর্ভাগ্যক্রমে জিসিসি এবং ঝনঝন এটি ছাড়া এটি করবে না -ffast-math

এফপি থেকে / এও সাবধান থাকুন unsigned এক্সপি / দীর্ঘ দীর্ঘ x86 (এভিএক্স 512 ব্যতীত) এর চেয়ে কম দক্ষ। একটি 64-বিট মেশিনে 32-বিট স্বাক্ষরবিহীন রূপান্তরটি বেশ সস্তা; কেবল 64৪-বিট স্বাক্ষরিত এবং সংক্ষিপ্ত আকারে রূপান্তর করুন। তবে অন্যথায় এটি উল্লেখযোগ্যভাবে ধীর।

  • x86 এর সাথে ঝাঁকুনি ছাড়াই / ছাড়াই -ffast-math -msse4.1: (int/long)rintইনলাইনগুলি roundsd/ এ cvttsd2si। (অপ্টিমাইজেশন থেকে মিস cvtsd2si)। lrintমোটেই ইনলাইন করে না।

  • x86 gcc6.x এবং এর আগে ছাড়া -ffast-math : কোনওভাবেই ইনলাইন নেই

  • x86 জিসিসি 7 ছাড়াই -ffast-math: (int/long)rintরাউন্ড এবং পৃথকভাবে রূপান্তরিত হয় ( এসএসই 4.1 এর মোট 2 টি নির্দেশাবলীর সাহায্যে সক্ষম করা হয়েছে, অন্যথায় কোডগুলির একটি গোছা rintছাড়াইroundsd )। lrintইনলাইন হয় না।
  • x86 জিসিসি সহ -ffast-math : সমস্ত উপায়ে ইনলাইন cvtsd2si(অনুকূল) , এসএসই 4.1 এর প্রয়োজন নেই।

  • AArch64 gcc6.3 ছাড়াই -ffast-math:(int/long)rint 2 নির্দেশাবলীতে ইনলাইন। lrintইনলাইন হয় না

  • AArch64 gcc6.3 এর সাথে -ffast-math: (int/long)rintএকটি কলটিতে সংকলন করে lrintlrintইনলাইন হয় না। আমরা দুটি নির্দেশনা না পেলে এটি একটি মিসড অপটিমাইজেশন হতে পারে -ffast-math

টোডো: গডবোল্টে আইসিসি এবং এমএসভিসি পাওয়া যায়, তবে আমি এর জন্য তাদের ফলাফলের দিকে নজর দিইনি। সম্পাদনাগুলি স্বাগত জানায় ... এছাড়াও: প্রথমে সংকলক / সংস্করণ এবং তার মধ্যে ফাংশন দ্বারা ভাঙ্গা কি আরও দরকারী হবে? বেশিরভাগ লোকেরা FP-> FP বা FP-> পূর্ণসংখ্যার বৃত্তাকার কতটা সংকলন করে তার উপর ভিত্তি করে সংকলকগুলি স্যুইচ করতে যাচ্ছেন না।
পিটার

2
rint()এটি সম্ভবত একটি সম্ভাব্য পছন্দ যেখানে সুপারিশ করার জন্য +1 which আমি অনুমান করি নামটি round()কিছু প্রোগ্রামারকে বোঝায় যে তারা এটি চায়, যদিও এটি rint()রহস্যজনক মনে হয়। নোট করুন যে round()একটি "ফানকি" রাউন্ডিং মোড ব্যবহার করে না: রাউন্ড-টু-নিকটতম-বন্ধনগুলি একটি সরকারী আইইইই -754 (২০০৮) রাউন্ডিং মোড। এটা তোলে জানতে আগ্রহী যে nearbyint()inlined না হয়ে যায়, দেওয়া এটি মূলত হিসাবে একই যে rint(), এবং হওয়া উচিত অভিন্ন অধীনে -ffast-mathশর্ত। এটি আমার কাছে বাগ-ইশ দেখাচ্ছে।
njuffa

4

সাবধান floor(x+0.5)। এখানে বিভেদ সংখ্যার জন্য কি ঘটতে পারে তা [2 ^ 52,2 ^ 53]:

-bash-3.2$ cat >test-round.c <<END

#include <math.h>
#include <stdio.h>

int main() {
    double x=5000000000000001.0;
    double y=round(x);
    double z=floor(x+0.5);
    printf("      x     =%f\n",x);
    printf("round(x)    =%f\n",y);
    printf("floor(x+0.5)=%f\n",z);
    return 0;
}
END

-bash-3.2$ gcc test-round.c
-bash-3.2$ ./a.out
      x     =5000000000000001.000000
round(x)    =5000000000000001.000000
floor(x+0.5)=5000000000000002.000000

এটি হল http://bugs.squeak.org/view.php?id=7134 । @ কননিকের মতো একটি সমাধান ব্যবহার করুন।

আমার নিজস্ব শক্তিশালী সংস্করণটি এমন হবে:

double round(double x)
{
    double truncated,roundedFraction;
    double fraction = modf(x, &truncated);
    modf(2.0*fraction, &roundedFraction);
    return truncated + roundedFraction;
}

মেঝে এড়ানোর আরও একটি কারণ (x + 0.5) এখানে দেওয়া হল


2
ডাউনওয়েটস সম্পর্কে জানতে আগ্রহী। টাইটি নিকটবর্তী এমনকি সমান হওয়ার চেয়ে শূন্য থেকে দূরে সমাধান হওয়ার কারণে?
aka.nice

1
দ্রষ্টব্য: সি স্পেসে বলা হয়েছে "বর্তমান গোলাকার দিক নির্বিশেষে শূন্য থেকে অর্ধেকটি কেস দূরে অবস্থিত।"
chux - মনিকা পুনরায় ইনস্টল করুন

4

আপনি যদি শেষ পর্যন্ত doubleআপনার round()ফাংশনটির আউটপুটটিকে একটিতে রূপান্তর করতে চান int, তবে এই প্রশ্নের গৃহীত সমাধানগুলি দেখতে এরকম কিছু দেখবে:

int roundint(double r) {
  return (int)((r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5));
}

যখন অভিন্ন র্যান্ডম মানগুলিতে পাস করা হয় তখন আমার মেশিনে প্রায় 8.88 এনএস এ ঘড়িগুলি থাকে ।

নীচে কার্যত সমতুল্য, যতদূর আমি বলতে পারি, তবে একটি উল্লেখযোগ্য পারফরম্যান্স সুবিধার জন্য আমার মেশিনে 2.48 এনএস এ ঘড়ি রয়েছে :

int roundint (double r) {
  int tmp = static_cast<int> (r);
  tmp += (r-tmp>=.5) - (r-tmp<=-.5);
  return tmp;
}

উন্নত পারফরম্যান্সের কারণগুলির মধ্যে হ'ল বাদ দেওয়া।


এর ব্যাপ্তির সীমার বাইরে অপরিবর্তিত আচরণ রয়েছে int। (এক্স 86 উপর বাস্তবে, আউট-অফ-পরিসীমা FP মান করা হবে CVTTSD2SIউত্পাদন0x80000000 পূর্ণসংখ্যা বিট প্যাটার্ন, অর্থাত হিসাবে INT_MIN, যা রূপান্তরিত ফিরে আসবে double
পিটার Cordes

2

কোনও কিছুর বাস্তবায়ন করার দরকার নেই, তাই আমি নিশ্চিত নই কেন এত উত্তরগুলি সংজ্ঞায়িত, ফাংশন, বা পদ্ধতিগুলির সাথে জড়িত।

সি 99 এ

টাইপ-জেনেরিক ম্যাক্রোগুলির জন্য আমাদের নিম্নলিখিত এবং এবং শিরোনাম <tgmath.h> রয়েছে।

#include <math.h>
double round (double x);
float roundf (float x);
long double roundl (long double x);

আপনি যদি এটি সঙ্কলন করতে না পারেন তবে আপনি সম্ভবত গণিতের পাঠাগারটি রেখে গেছেন। এটির অনুরূপ একটি কমান্ড আমার প্রতিটি সি সংকলক (বেশ কয়েকটি) তে কাজ করে।

gcc -lm -std=c99 ...

সি ++ 11 এ

আমাদের # অন্তর্ভুক্ত <cmath> এ নিম্নলিখিত এবং অতিরিক্ত ওভারলোড রয়েছে যা আইইইই ডাবল স্পষ্টতা ভাসমান পয়েন্টের উপর নির্ভর করে।

#include <math.h>
double round (double x);
float round (float x);
long double round (long double x);
double round (T x);

স্ট্যান্ডার্ড নেমস্পেসেও সমান পরিমাণ রয়েছে ।

আপনি যদি এটি সংকলন করতে না পারেন তবে আপনি সি ++ এর পরিবর্তে সি সংকলনটি ব্যবহার করতে পারেন। নিম্নলিখিত বুনিয়াদি কমান্ডটি g ++ 6.3.1, x86_64-w64-mingw32-g ++ 6.3.0, ঝাঁকুনি- x86_64 ++ 3.8.0, এবং ভিজ্যুয়াল সি ++ 2015 সম্প্রদায় নিয়ে ত্রুটি বা সতর্কতা তৈরি করে না।

g++ -std=c++11 -Wall

অর্ডিনাল বিভাগ সহ

দুটি অর্ডিনাল সংখ্যাকে বিভাজন করার সময়, যেখানে টি সংক্ষিপ্ত, অন্তর্, দীর্ঘ বা অন্য কোনও অর্ডিনাল, বৃত্তাকার প্রকাশটি এটি।

T roundedQuotient = (2 * integerNumerator + 1)
    / (2 * integerDenominator);

সঠিকতা

ভাসমান পয়েন্ট অপারেশনগুলিতে অদ্ভুত সন্ধানের অসম্পূর্ণতা উপস্থিত হওয়ার কোনও সন্দেহ নেই, তবে এটি কেবল তখনই সংখ্যাগুলি উপস্থিত হয় এবং বৃত্তাকার সাথে সামান্য যোগসূত্র থাকে।

উত্সটি কেবলমাত্র ভাসমান পয়েন্ট সংখ্যার আইইইই প্রতিনিধিত্বের মন্টিসায় উল্লেখযোগ্য সংখ্যার সংখ্যা নয়, এটি মানুষ হিসাবে আমাদের দশমিক চিন্তার সাথে সম্পর্কিত।

দশটি পাঁচ এবং দু'জনের পণ্য এবং 5 এবং 2 অপেক্ষাকৃত প্রধান। সুতরাং আইইইই ভাসমান পয়েন্ট স্ট্যান্ডার্ডগুলি সম্ভবত সমস্ত বাইনারি ডিজিটাল উপস্থাপনার জন্য দশমিক সংখ্যা হিসাবে নিখুঁতভাবে উপস্থাপন করা যায় না।

এটি গোলাকার আলগোরিদিমগুলির সাথে কোনও সমস্যা নয়। এটি গাণিতিক বাস্তবতা যা ধরণের নির্বাচনের সময় এবং গণনার নকশা, ডেটা এন্ট্রি এবং সংখ্যার প্রদর্শনের সময় বিবেচনা করা উচিত। যদি কোনও অ্যাপ্লিকেশন এই দশমিক-বাইনারি রূপান্তর সংক্রান্ত সমস্যাগুলি দেখায় এমন অঙ্কগুলি প্রদর্শন করে, তবে অ্যাপ্লিকেশনটি দৃশ্যত নির্ভুলতা প্রকাশ করছে যা ডিজিটাল বাস্তবতায় নেই এবং এটি পরিবর্তন করা উচিত।


1
"আমি নিশ্চিত নই কেন এত উত্তরগুলিতে সংজ্ঞা, ফাংশন বা পদ্ধতি জড়িত।" কখন জিজ্ঞাসা করা হয়েছিল তা একবার দেখুন - সি ++ 11 এখনও বের হয়নি। ;)
জাজডস্পায়ার

@ জেগডস্পায়ার, আপনার পক্ষে যদি এটি যথাযথ মনে হয় তবে ভালভাবে আমাকে থাম্বস আপ করুন, কারণ উচ্চতর স্কোরিংয়ের সমস্ত উত্তর আজকের সর্বাধিক ব্যবহৃত সংকলকগুলির প্রসঙ্গে অপ্রচলিত এবং বিভ্রান্তিকর।
ফৌচ্রিস্টিয়ান

2

ফাংশন double round(double)ব্যবহারের সাথে modfফাংশন:

double round(double x)
{
    using namespace std;

    if ((numeric_limits<double>::max() - 0.5) <= x)
        return numeric_limits<double>::max();

    if ((-1*std::numeric_limits<double>::max() + 0.5) > x)
        return (-1*std::numeric_limits<double>::max());

    double intpart;
    double fractpart = modf(x, &intpart);

    if (fractpart >= 0.5)
        return (intpart + 1);
    else if (fractpart >= -0.5)
        return intpart;
    else
        return (intpart - 1);
    }

সংকলন পরিষ্কার করতে "math.h" এবং "সীমা" অন্তর্ভুক্ত করা আবশ্যক। ফাংশনটি নিম্নলিখিত রাউন্ডিং স্কিমা অনুযায়ী কাজ করে:

  • 5.0 এর রাউন্ডটি 5.0
  • 3.8 এর রাউন্ডটি 4.0
  • 2.3 এর রাউন্ডটি 2.0
  • 1.5 এর রাউন্ডটি 2.0
  • 0.501 এর রাউন্ড 1.0
  • 0.5 এর রাউন্ড 1.0
  • 0.499 এর গোলটি 0.0 হয়
  • 0.01 এর বৃত্ত 0.0 হয়
  • 0.0 এর বৃত্ত 0.0 হয়
  • -0.01 এর রাউন্ড -0.0
  • -0.499 এর রাউন্ড -0.0
  • -0.5 এর রাউন্ড -0.0
  • -0.501 এর রাউন্ড -1.0
  • -1.5 এর রাউন্ডটি -1.0
  • -২.৩ এর রাউন্ড -২.০
  • -৩.৮ এর গোলটি -৪.০
  • -5.0 এর রাউন্ড -5.0 হয়

2
এটি একটি ভাল সমাধান। আমি নিশ্চিত নই যে রাউন্ডিং -1.5 থেকে -1.0 মানক যদিও আমি সিমেট্রি দ্বারা -2.0 আশা করব। এছাড়াও আমি অগ্রণী গার্ডের পয়েন্টটি দেখতে পাচ্ছি না, যদি প্রথম দুটি অপসারণ করা যায়।
ওরফে.নিস

2
আমি আইএসও / আইইসি 10967-2 স্ট্যান্ডার্ড, ওপেন-std.org/jtc1/sc22/wg11/docs/n462.pdf এ এবং পরিশিষ্ট B.5.2.4 থেকে দেখেছি, গোলাকার কার্যটি অবশ্যই সত্যসম্মত, গোলাকার_এফ (এক্স) = হওয়া উচিত নেগ_এফ (গোলিং_এফ (নেগ_এফ (এক্স)))
ওরফে.নিস

এই ধীর সি ++ 11 তুলনা করা যেতে যাচ্ছে rint()বা nearbyint(), কিন্তু আপনি সত্যিই একটি কম্পাইলার একটি সঠিক রাউন্ডইং ফাংশন প্রদান করে যে ব্যবহার করতে পারবেন না যদি, এবং আপনি কর্মক্ষমতা চেয়ে বেশি স্পষ্টতা প্রয়োজন ...
পিটার Cordes

1

আপনি যদি সি ++ 11 স্ট্যান্ডার্ডকে সমর্থন করে এমন পরিবেশগুলিতে কোড সংকলন করতে সক্ষম হতে চান তবে এটির সমর্থন করে না এমন পরিবেশে একই কোডটি সংকলন করতে সক্ষম হতে হবে তবে আপনি স্ট্যান্ডার্ডের মধ্যে একটি ফাংশন ম্যাক্রো ব্যবহার করতে পারেন :: বৃত্তাকার () এবং প্রতিটি সিস্টেমের জন্য একটি কাস্টম ফাংশন। কেবল পাস করুন -DCPP11বা /DCPP11সি ++ 11-অনুবর্তী কম্পাইলারকে (বা এর অন্তর্নির্মিত সংস্করণ ম্যাক্রো ব্যবহার করুন) এবং এর মতো শিরোনাম করুন:

// File: rounding.h
#include <cmath>

#ifdef CPP11
    #define ROUND(x) std::round(x)
#else    /* CPP11 */
    inline double myRound(double x) {
        return (x >= 0.0 ? std::floor(x + 0.5) : std::ceil(x - 0.5));
    }

    #define ROUND(x) myRound(x)
#endif   /* CPP11 */

দ্রুত উদাহরণের জন্য দেখুন http://ideone.com/zal709

এটি -0.0 এর জন্য সাইন বিট সংরক্ষণ সহ সি ++ 11-অনুবর্তী নয় এমন পরিবেশে স্ট্যান্ড :: গোল () প্রায় অনুমান করে। তবে এটি সামান্য পারফরম্যান্স হিট হতে পারে এবং সম্ভবত 0.4999999999999999994 বা অনুরূপ মানগুলির মতো নির্দিষ্ট "সমস্যা" ভাসমান-পয়েন্টের মানগুলি গোল করার সমস্যা রয়েছে।

বিকল্পভাবে, আপনি যদি একটি সি ++ 11- কমপ্লায়েন্ট কম্পাইলার অ্যাক্সেস পেয়ে থাকেন তবে আপনি কেবল এটির <cmath>শিরোনাম থেকে স্ট্যান্ড :: বৃত্তাকার () দখল করতে পারেন এবং এটি আপনার নিজের শিরোনাম তৈরি করতে ব্যবহার করতে পারেন যা ফাংশনটি এটি ইতিমধ্যে সংজ্ঞায়িত না হলে সংজ্ঞায়িত করে। নোট করুন যে এটি সর্বোত্তম সমাধান নাও হতে পারে, বিশেষত, যদি আপনাকে একাধিক প্ল্যাটফর্মের জন্য সংকলন করতে হয়।


1

ক্যালাক্সির প্রতিক্রিয়ার ভিত্তিতে, নিম্নলিখিতটি একটি টেম্প্লেটেড সমাধান যা কোনও ভাসমান পয়েন্ট সংখ্যাটিকে প্রাকৃতিক বৃত্তাকারের উপর ভিত্তি করে নিকটতম পূর্ণসংখ্যার ধরণের দিকে গোল করে। মানটি পূর্ণসংখ্যার ধরণের পরিসীমা থেকে বাইরে থাকলে ডিবাগ মোডে ত্রুটিও ছুঁড়ে দেয়, যার ফলে এটি প্রায় একটি কার্যকর লাইব্রেরি ফাংশন হিসাবে পরিবেশন করে।

    // round a floating point number to the nearest integer
    template <typename Arg>
    int Round(Arg arg)
    {
#ifndef NDEBUG
        // check that the argument can be rounded given the return type:
        if (
            (Arg)std::numeric_limits<int>::max() < arg + (Arg) 0.5) ||
            (Arg)std::numeric_limits<int>::lowest() > arg - (Arg) 0.5)
            )
        {
            throw std::overflow_error("out of bounds");
        }
#endif

        return (arg > (Arg) 0.0) ? (int)(r + (Arg) 0.5) : (int)(r - (Arg) 0.5);
    }

1
আমি আমার উত্তরে উল্লেখ করেছি যেহেতু 0.5সব ক্ষেত্রে কার্যকর হয় না। যদিও কমপক্ষে আপনি ওভারফ্লো সমস্যাটি মোকাবেলা করেন যাতে আপনি অপরিজ্ঞাত আচরণ এড়ান।
শফিক ইয়াঘমোর

1

মতামত এবং অন্যান্য উত্তরে নির্দেশিত হিসাবে, আইএসও সি ++ round()স্ট্যান্ডার্ড গণিত লাইব্রেরিটি উল্লেখ করে যখন এই ফাংশনটি টানানো হয়েছিল তখন আইএসও সি ++ স্ট্যান্ডার্ড গ্রন্থাগারটি যুক্ত করা হয়নি ।

ইতিবাচক operands [গণমাধ্যমে জন্য UB ] round(x) == floor (x + 0.5), যেখানে UB 2 23 জন্য floatযখন আইইইই-754 (2008) ম্যাপ binary32, এবং 2 52 জন্য doubleযখন এটি আইইইই-754 (2008) ম্যাপ করা হয় binary64। এই দুটি ভাসমান-বিন্দু বিন্যাসে 23 এবং 52 সংখ্যাগুলি সঞ্চিত ম্যান্টিসা বিটের সংখ্যার সাথে মিলে যায় । [+0, ½) round(x) == 0, এবং ( ইউবি , + ∞] তে ধনাত্মক অপারেন্ডগুলির জন্য round(x) == x। ফাংশনটি এক্স-অক্ষের প্রতিসাম্যপূর্ণ হওয়ায়, নেতিবাচক যুক্তিগুলি xঅনুযায়ী পরিচালনা করা যেতে পারে round(-x) == -round(x)

এটি নীচে কমপ্যাক্ট কোডে বাড়ে। এটি বিভিন্ন প্ল্যাটফর্ম জুড়ে যুক্তিসঙ্গত সংখ্যক নির্দেশাবলীর সংকলন করে। আমি জিপিইউতে সর্বাধিক কমপ্যাক্ট কোড পর্যবেক্ষণ করেছি, যেখানে my_roundf()প্রায় এক ডজন নির্দেশিকা প্রয়োজন। প্রসেসরের আর্কিটেকচার এবং সরঞ্জামচেইনের উপর নির্ভর করে, এই ভাসমান-পয়েন্ট ভিত্তিক পদ্ধতির ভিন্ন উত্তরে রেফারেন্সযুক্ত নিউলিব থেকে পূর্ণসংখ্যার ভিত্তিক প্রয়োগের চেয়ে দ্রুত বা ধীর হতে পারে ।

আমি ইনটেল সংকলক সংস্করণ 13 এবং উভয় ব্যবহার my_roundf()করে newlib roundf()প্রয়োগের বিরুদ্ধে বিস্মৃতভাবে পরীক্ষা করেছি । আমিও চেক করা যে newlib সংস্করণটি মিলে মধ্যে ইন্টেল কম্পাইলার লাইব্রেরি। দ্বৈত-নির্ভুলতার জন্য এক্সহসিউটিভ টেস্টিং সম্ভব নয় , তবে কোডটি একক-নির্ভুল প্রয়োগের জন্য কাঠামোগতভাবে অভিন্ন।/fp:strict/fp:fastroundf()mathimfround()

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>

float my_roundf (float x)
{
    const float half = 0.5f;
    const float one = 2 * half;
    const float lbound = half;
    const float ubound = 1L << 23;
    float a, f, r, s, t;
    s = (x < 0) ? (-one) : one;
    a = x * s;
    t = (a < lbound) ? x : s;
    f = (a < lbound) ? 0 : floorf (a + half);
    r = (a > ubound) ? x : (t * f);
    return r;
}

double my_round (double x)
{
    const double half = 0.5;
    const double one = 2 * half;
    const double lbound = half;
    const double ubound = 1ULL << 52;
    double a, f, r, s, t;
    s = (x < 0) ? (-one) : one;
    a = x * s;
    t = (a < lbound) ? x : s;
    f = (a < lbound) ? 0 : floor (a + half);
    r = (a > ubound) ? x : (t * f);
    return r;
}

uint32_t float_as_uint (float a)
{
    uint32_t r;
    memcpy (&r, &a, sizeof(r));
    return r;
}

float uint_as_float (uint32_t a)
{
    float r;
    memcpy (&r, &a, sizeof(r));
    return r;
}

float newlib_roundf (float x)
{
    uint32_t w;
    int exponent_less_127;

    w = float_as_uint(x);
    /* Extract exponent field. */
    exponent_less_127 = (int)((w & 0x7f800000) >> 23) - 127;
    if (exponent_less_127 < 23) {
        if (exponent_less_127 < 0) {
            /* Extract sign bit. */
            w &= 0x80000000;
            if (exponent_less_127 == -1) {
                /* Result is +1.0 or -1.0. */
                w |= ((uint32_t)127 << 23);
            }
        } else {
            uint32_t exponent_mask = 0x007fffff >> exponent_less_127;
            if ((w & exponent_mask) == 0) {
                /* x has an integral value. */
                return x;
            }
            w += 0x00400000 >> exponent_less_127;
            w &= ~exponent_mask;
        }
    } else {
        if (exponent_less_127 == 128) {
            /* x is NaN or infinite so raise FE_INVALID by adding */
            return x + x;
        } else {
            return x;
        }
    }
    x = uint_as_float (w);
    return x;
}

int main (void)
{
    uint32_t argi, resi, refi;
    float arg, res, ref;

    argi = 0;
    do {
        arg = uint_as_float (argi);
        ref = newlib_roundf (arg);
        res = my_roundf (arg);
        resi = float_as_uint (res);
        refi = float_as_uint (ref);
        if (resi != refi) { // check for identical bit pattern
            printf ("!!!! arg=%08x  res=%08x  ref=%08x\n", argi, resi, refi);
            return EXIT_FAILURE;
        }
        argi++;
    } while (argi);
    return EXIT_SUCCESS;
}

আমি int16 বিটের চেয়ে বেশি বিস্তৃত ধরে নেওয়া এড়াতে একটি সম্পাদনা করেছি । এটি এখনও অবশ্যই ধরে floatনিচ্ছে যে 4-বাইট আইইইই 7575 বাইনারি 32। একটি সি ++ 11 static_assertবা একটি ম্যাক্রো #ifdef/ #errorএটি চেক করতে পারে। (তবে অবশ্যই যদি সি ++ 11 উপলভ্য থাকে তবে আপনার ব্যবহার করা উচিত std::round, বা বর্তমান রাউন্ডিং মোড ব্যবহারের জন্য std::rintযা জিসিসি এবং বিড়ম্বনার সাথে সুন্দরভাবে ইনলাইন করে)।
পিটার কর্ডেস

BTW, gcc -ffast-math -msse4.1inlines std::round()একটি থেকে add( AND(x, L1), OR(x,L2)এবং তারপর একটি roundsd। অর্থাত্ এটি নিখুঁতভাবে দক্ষতার সাথে প্রয়োগ roundকরে rint। তবে সি ++ উত্সটিতে ম্যানুয়ালি এটি করার কোনও কারণ নেই, কারণ আপনার যদি থাকে std::rint()বা std::nearbyint()আপনারও থাকে std::round()। গডবোল্ট লিঙ্কের জন্য আমার উত্তর এবং বিভিন্ন জিসিসি / কলং সংস্করণগুলির সাথে ইনলাইনগুলি না কী রয়েছে তার একটি রুনডাউন দেখুন।
পিটার কর্ডেস

@ পিটারকর্ডস আমি কীভাবে round()কার্যকরভাবে প্রয়োগ করতে পারি সে সম্পর্কে আমি ভালভাবে অবগত rint()(যখন পরবর্তীকরা মোড-টু-নিকটস্থ-বা-এমনকি-মোডে কাজ করছে): আমি এটি সিউডিএ স্ট্যান্ডার্ড গণিত গ্রন্থাগারের জন্য প্রয়োগ করেছি। যাইহোক, এই প্রশ্নটি round()সি ++ 11 এর পূর্বে সি ++ দিয়ে কীভাবে প্রয়োগ করবেন তা জিজ্ঞাসা করেছিল , সুতরাং rint()কেবল floor()এবং কেবলমাত্র উপলভ্য হবে না ceil()
njuffa

@ পিটারকর্ডস দুঃখিত, আমি ভুল বলছি। round()সহজে থেকে সংশ্লেষিত হয় rint()মধ্যে বৃত্তাকার টু শূন্য মোড, ওরফে trunc()। প্রথম কফির আগে প্রতিক্রিয়া জানানো উচিত ছিল না।
njuffa

1
@ পিটারকর্ডস আমি সম্মত হই যে সম্ভবত এটি সম্ভব যে ওপির নির্দিষ্ট বৃত্তাকারী আচরণের প্রয়োজন নেই round(); বেশির ভাগ প্রোগ্রামাররা কেবল মধ্যে পার্থক্য সচেতন নয় round()বনাম rint()বৃত্তাকার টু নিকটতম-এমনকি, যেখানে আধুনিক সাধারণত হার্ডওয়্যার এবং সেইজন্য আরো দক্ষ করে সরাসরি প্রদান করা হয় সঙ্গে; প্রোগ্রামারদের সচেতন করার জন্য আমি সিইউডিএ প্রোগ্রামিং গাইডে এটি বানান দিয়েছিলাম: "একক নির্ভুলতা ভাসমান-পয়েন্ট অপারেণ্ডকে একটি পূর্ণসংখ্যার সাথে গোল করার প্রস্তাব দেওয়া উপায়, ফলাফলটি একক নির্ভুলতা ভাসমান-পয়েন্ট সংখ্যা হিসাবে হয় rintf()না, roundf()"।
njuffa

0

আমি x86 আর্কিটেকচার এবং এমএস ভিএস নির্দিষ্ট সি ++ এর জন্য asm এ নিম্নলিখিত প্রয়োগটি ব্যবহার করি:

__forceinline int Round(const double v)
{
    int r;
    __asm
    {
        FLD     v
        FISTP   r
        FWAIT
    };
    return r;
}

ইউপিডি: দ্বিগুণ মান ফেরত

__forceinline double dround(const double v)
{
    double r;
    __asm
    {
        FLD     v
        FRNDINT
        FSTP    r
        FWAIT
    };
    return r;
}

আউটপুট:

dround(0.1): 0.000000000000000
dround(-0.1): -0.000000000000000
dround(0.9): 1.000000000000000
dround(-0.9): -1.000000000000000
dround(1.1): 1.000000000000000
dround(-1.1): -1.000000000000000
dround(0.49999999999999994): 0.000000000000000
dround(-0.49999999999999994): -0.000000000000000
dround(0.5): 0.000000000000000
dround(-0.5): -0.000000000000000

ফলাফলের মানটি ডাবল নির্ভুলতার সাথে ভাসমান পয়েন্টের মান হওয়া উচিত।
সত্যচর্চা

@ ট্রুথসিকার: হ্যাঁ, আমাকে প্রয়োজনীয় ধরণের রিটার্ন মান দেখতে হয়েছিল। ঠিক আছে, "ইউপিডি" দেখুন।
আলেক্সি এফ।

কম্পাইলার আশা ইনলাইন হবে rint()বা nearbyint()একটি SSE4.1 করার roundsdনির্দেশ অথবা একটি x87 frndintনির্দেশ, যা অনেক দ্রুত দুই দোকান / রিলোড বৃত্তাকার একটি রেজিস্টার ডাটা এই ইনলাইন এ এস এম ব্যবহার করা প্রয়োজন ভ্রমণের চেয়ে থাকবে। এমএসভিসি ইনলাইন asm একক নির্দেশাবলী মোড়ানোর জন্য যথেষ্ট পরিমাণে চুষে ফেলে frndintকারণ কোনও রেজিস্টারে ইনপুট পাওয়ার কোনও উপায় নেই। ফলাফলের সাথে একটি ফাংশন শেষে এটি ব্যবহার করা st(0)আউটপুট ফেরত দেওয়ার উপায় হিসাবে নির্ভরযোগ্য হতে পারে; স্পষ্টতই এটি eaxপূর্ণসংখ্যার জন্য নিরাপদ , এমনকি যখন এটি আসমযুক্ত ফাংশনটি ইনলাইন করে।
পিটার কর্ডেস

@ পিটারকর্ডস আধুনিক অপ্টিমাইজেশান স্বাগত। তবে আমি এসএসই 4.1 ব্যবহার করতে পারিনি কারণ এ মুহূর্তে এটি বিদ্যমান ছিল না। আমার উদ্দেশ্যটি ছিল রাউন্ডের সর্বনিম্ন বাস্তবায়ন প্রদান করা যা 2000 এর দশক থেকে এমনকি পুরানো ইন্টেল P3 বা P4 পরিবারগুলিতেও কাজ করতে পারে।
আলেক্সি এফ।

পি 3 এর কাছে এসএসই 2ও নেই, তাই সংকলকটি ইতিমধ্যে এর জন্য x87 ব্যবহার করবে doubleএবং সুতরাং এটির জন্য frndintনিজেই নির্গত করতে সক্ষম হওয়া উচিত rint()। যদি আপনার সংকলক এসএসই 2 ব্যবহার করে থাকে তবে doubleএক্সএমএম রেজিস্টার থেকে x87 এ পিছনে বাউন করা উপযুক্ত নয়।
পিটার কর্ডেস

0

দশমিক স্থানে "এন" দশমিক স্থানে ভাসমান মানকে গোল করার সর্বোত্তম উপায়, ও (1) সময় অনুসারে নিম্নরূপ: -

আমাদের মানটি তিনটি স্থানে করতে হবে অর্থাৎ n = 3. তাই,

float a=47.8732355;
printf("%.3f",a);

-4
// Convert the float to a string
// We might use stringstream, but it looks like it truncates the float to only
//5 decimal points (maybe that's what you want anyway =P)

float MyFloat = 5.11133333311111333;
float NewConvertedFloat = 0.0;
string FirstString = " ";
string SecondString = " ";
stringstream ss (stringstream::in | stringstream::out);
ss << MyFloat;
FirstString = ss.str();

// Take out how ever many decimal places you want
// (this is a string it includes the point)
SecondString = FirstString.substr(0,5);
//whatever precision decimal place you want

// Convert it back to a float
stringstream(SecondString) >> NewConvertedFloat;
cout << NewConvertedFloat;
system("pause");

এটি রূপান্তরকরণের অকার্যকর নোংরা উপায় হতে পারে তবে হেক, এটি বেশ কার্যকর। এবং এটি ভাল, কারণ এটি আসল ফ্লোটের জন্য প্রযোজ্য। কেবল আউটপুটটি চাক্ষুষভাবে প্রভাবিত করছে না।


এটি হাস্যকরভাবে অদক্ষ এবং এটি নিকটে কাছাকাছি গোল করার পরিবর্তে (সর্বদা পেছনের অঙ্কগুলি বর্জন করে) কেটে যায়।
পিটার

-6

আমি এটা করেছি:

#include <cmath.h>

using namespace std;

double roundh(double number, int place){

    /* place = decimal point. Putting in 0 will make it round to whole
                              number. putting in 1 will round to the
                              tenths digit.
    */

    number *= 10^place;
    int istack = (int)floor(number);
    int out = number-istack;
    if (out < 0.5){
        floor(number);
        number /= 10^place;
        return number;
    }
    if (out > 0.4) {
        ceil(number);
        number /= 10^place;
        return number;
    }
}

3
আপনি বাইনারি অপারেটরের চেয়ে 10 ^ স্থানে পাউ (10, স্থান) বোঝাতে চাইছেন না? আমার মেশিনে 10 ^ 2 আমাকে 8 দেয়! তবুও আমার ম্যাক 10.7.4 এবং জিসিসি তে কোডটি কার্যকর হয় না, আসল মানটি ফেরায়।
পিট 855217
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.