2013-02-22 7 views
1

у меня есть следующий код, чтобы закруглить валютномокругления валюты

function MyRound(value :currency) : integer; 

begin 
    if value > 0 then 
    result := Trunc(value + 0.5) 
    else 
    result := Trunc(value - 0.5); 
end; 

он работал хорошо до сих пор, моя проблема теперь, если я хочу, чтобы округлить валюту как 999999989000,40 это дает отрицательное значение, так как Truc принимает int и MyRound также возвращает int.

Мои возможные решения - конвертировать валюту в строку и получить строку до . и конвертировать строку обратно в валюту. Правильно ли это? Я новичок в delpi, поэтому PLS мне помогает.

+2

использовать int64 вместо целого? –

+1

Решение, которое вы предлагаете, неверно и не будет работать, потому что ваша проблема связана с 32-разрядным переполнением. – kludg

ответ

4

Вы являетесь слишком сложными вопросами. Вы можете просто использовать Round:

program Project1; 
{$APPTYPE CONSOLE} 

uses 
    SysUtils; 

var 
    C: Currency; 

begin 
    C := 999999989000.4; 
    Writeln(Round(C)); 
    C := 999999989000.5; 
    Writeln(Round(C)); 
    C := 999999989000.6; 
    Writeln(Round(C)); 
    C := 999999989001.4; 
    Writeln(Round(C)); 
    C := 999999989001.5; 
    Writeln(Round(C)); 
    C := 999999989001.6; 
    Writeln(Round(C)); 
    Readln; 
end. 

, который выводит

 
999999989000 
999999989000 
999999989001 
999999989001 
999999989002 
999999989002 

Если вы не хотите, округления банкира, и вы действительно хотите, чтобы ваша Trunc логика, то вам нужно написать свою собственную функцию. Но проблема с вашей функцией в том, что она усекалась до 32-битного целого. Убедитесь, функция возвращает 64 битное целое число:

program Project1; 
{$APPTYPE CONSOLE} 

uses 
    SysUtils, Math; 

var 
    C: Currency; 

function MyRound(const Value: Currency): Int64; 
begin 
    if Value > 0 then 
    result := Trunc(Value + 0.5) 
    else 
    result := Trunc(Value - 0.5); 
end; 

begin 
    C := 999999989000.4; 
    Writeln(MyRound(C)); 
    C := 999999989000.5; 
    Writeln(MyRound(C)); 
    C := 999999989000.6; 
    Writeln(MyRound(C)); 
    C := 999999989001.4; 
    Writeln(MyRound(C)); 
    C := 999999989001.5; 
    Writeln(MyRound(C)); 
    C := 999999989001.6; 
    Writeln(MyRound(C)); 
    Readln; 
end. 
 
999999989000 
999999989001 
999999989001 
999999989001 
999999989002 
999999989002 
+4

Doesn «t раунд страдает от округления банкиров, где 2,5 идет до 2 и 3,5 идет до 4? (Или наоборот, никогда не помню). 0,5 трюк - это самый простой способ обойти это без беспорядка с настройками FPU? –

+2

@ MarjanVenema Ну, вот как работает «Круглый». Если вам нужно что-то другое, то используйте что-то другое. –

+6

Ну, вот как работают круглые работы с учетом стандартных настроек FPU.Дело не в том, как люди ожидают, что они будут работать, учитывая базовые математические знания, но не имеют финансовой основы. Меня это удивило, когда я узнал об этом ... –

6

С моей точки зрения, у вас есть два варианта:

  1. Вы используете функцию Round, как указывает Дэвид Heffernan;
  2. Вы можете использовать функцию SimpleRoundTo, как описано here. Преимущество SimpleRoundTo состоит в том, что он получает параметры типов данных Single, Double и Extended и преобразует круглые номера очень хорошо, как указано.

Вам не нужны преобразования типов. Есть много функций округления, которые уже доступны вам. Просто округлите желаемое число.

+1

Как 'SimpleRoundTo (..., 0)' отличается от 'Round (...)'? –

+0

@DavidHeffernan в этом случае, это не так. Вот почему я сказал, что ваше решение дает тот же результат. Однако имеет значение, если вы хотите округлить число до заданной точности. 'Round (...)' является частным случаем 'SimpleRoundTo (..., 0)' –

+1

@DavidHeffernan: Он не использует округление банкиров. Согласно документации, которую Богдан связал с «Результат этой функции зависит от текущего режима округления FPU ... Для округления в« режиме Banker »используйте System.Math.RoundTo». –

0

Это то, что я на самом деле использовать (очень хотелось бы услышать, если есть какие-либо проблемы с этим подходом!):

function RoundingFunction(X: Real): Int64; 
begin 
    Result := Trunc(SimpleRoundTo(X, 0)); 
end; 
+0

'SimpleRoundTo (x, 0)' не оставляет десятичных знаков, поэтому IMHO, функция 'Trunc' бесполезна там. –

+0

Компилятор не согласен –

+0

Не согласен с чем? –

0

Посмотрите на процедуры округления Джона Herbster в. Они предлагают практически любой тип округления вам может понадобиться, например:

drNone, {No rounding.} 
drHalfEven,{Round to nearest or to even whole number. (a.k.a Bankers) } 
drHalfPos, {Round to nearest or toward positive.} 
drHalfNeg, {Round to nearest or toward negative.} 
drHalfDown,{Round to nearest or toward zero.} 
drHalfUp, {Round to nearest or away from zero.} 
drRndNeg, {Round toward negative.     (a.k.a. Floor) } 
drRndPos, {Round toward positive.     (a.k.a. Ceil) } 
drRndDown, {Round toward zero.      (a.k.a. Trunc) } 
drRndUp); {Round away from zero.} 

Я не могу дать вам ссылку прямо сейчас, но Google: десятичное округление Джон Herbster Я думаю, что его последние процедуры округления в DecimalRounding_JH1.pas , Его обсуждение округления с плавающей точкой (где-то на веб-сайте Embarcadero является «обязательным»).

Смежные вопросы