source

숫자를 세 부분으로 나누고 그 총합을 원래의 숫자와 일치시키는 알고리즘이 있습니까?

manycodes 2023. 11. 2. 21:56
반응형

숫자를 세 부분으로 나누고 그 총합을 원래의 숫자와 일치시키는 알고리즘이 있습니까?

예를 들어 다음 예제를 고려할 경우.

100.00 - Original Number
33.33  - 1st divided by 3
33.33  - 2nd divided by 3
33.33  - 3rd divided by 3
99.99  - Is the sum of the 3 division outcomes

But i want it to match the original 100.00

제가 볼 수 있었던 한 가지 방법은 원래의 숫자에서 처음 두 분할을 뺀 것이었고 그 결과는 제 세 번째 숫자가 될 것입니다.이제 그 3개의 번호를 찍으면 원래 번호를 받습니다.

 100.00 - Original Number
  33.33 - 1st divided by 3
  33.33 - 2nd divided by 3
  33.34 - 3rd number
 100.00 - Which gives me my original number correctly. (33.33+33.33+33.34 = 100.00)

Oracle PL/SQL이나 구현 가능한 함수 등에서 이에 대한 공식이 있습니까?

미리 감사드립니다!

이 버전은 정밀도를 매개변수로 사용합니다.

with q as (select 100 as val, 3 as parts, 2 as prec from dual)
select rownum as no
      ,case when rownum = parts
       then val - round(val / parts, prec) * (parts - 1) 
       else round(val / parts, prec)
       end v
from   q
connect by level <= parts

no  v
=== =====
1   33.33
2   33.33
3   33.34

예를 들어 현재 월의 일 수에 값을 분할하려면 다음 작업을 수행할 수 있습니다.

with q as (select 100 as val
                 ,extract(day from last_day(sysdate)) as parts
                 ,2 as prec from dual)
select rownum as no
      ,case when rownum = parts
       then val - round(val / parts, prec) * (parts - 1) 
       else round(val / parts, prec)
       end v
from   q
connect by level <= parts;

1   3.33
2   3.33
3   3.33
4   3.33
...
27  3.33
28  3.33
29  3.33
30  3.43

각 월 간에 값을 할당하려면 대신 이 작업을 수행할 수 있습니다(변경).level <= 3계산된 개월 수를 변경하는 방법):

with q as (
  select add_months(date '2013-07-01', rownum-1) the_month
        ,extract(day from last_day(add_months(date '2013-07-01', rownum-1)))
         as days_in_month
        ,100 as val
        ,2 as prec
  from dual
  connect by level <= 3)
,q2 as (
  select the_month, val, prec
        ,round(val * days_in_month 
                     / sum(days_in_month) over (), prec)
         as apportioned
        ,row_number() over (order by the_month desc) 
         as reverse_rn
  from   q)
select the_month
      ,case when reverse_rn = 1
       then val - sum(apportioned) over (order by the_month
                  rows between unbounded preceding and 1 preceding)
       else apportioned
       end as portion
from q2;

01/JUL/13   33.7
01/AUG/13   33.7
01/SEP/13   32.6

유리수를 사용합니다.단순 값이 아닌 분수로 숫자를 저장할 수 있습니다.그렇게 해야 수량이 3으로 나뉘고 원래 수량과 합이 된다는 것을 확인할 수 있습니다.물론 라운딩과 남은 음식들을 가지고도 무리한 일을 할 수 있습니다. 정확히 3분으로 나누지 않아도 상관없다면 말입니다.

"알고리즘"은 단순히

100/3 + 100/3 + 100/3 == 300/3 == 100

분자와 분모를 모두 별도의 필드에 저장한 다음 분자를 추가합니다.값을 표시할 때 항상 부동 소수점으로 변환할 수 있습니다.

Oracle 문서에는 다음과 같은 구현 방법에 대한 좋은 예도 있습니다.

CREATE TYPE rational_type AS OBJECT
( numerator INTEGER,
  denominator INTEGER,
  MAP MEMBER FUNCTION rat_to_real RETURN REAL,
  MEMBER PROCEDURE normalize,
  MEMBER FUNCTION plus (x rational_type)
       RETURN rational_type);

다음은 매개 변수화된 SQL 버전입니다.

  SELECT COUNT (*), grp
    FROM (WITH input AS (SELECT 100 p_number, 3 p_buckets FROM DUAL),
               data
               AS (    SELECT LEVEL id, (p_number / p_buckets) group_size
                         FROM input
                   CONNECT BY LEVEL <= p_number)
          SELECT id, CEIL (ROW_NUMBER () OVER (ORDER BY id) / group_size) grp
            FROM data)
GROUP BY grp

출력:

COUNT(*)    GRP
33          1
33          2
34          3

입력 파라미터(p_number 및 p_buckets)를 편집하면 SQL은 기본적으로 요청된 버킷 수(p_buckets)에 p_number를 최대한 균등하게 분배합니다.

어제 시작번호에서 3개 중 2개를 빼고 100 - 33.33 - 33.33 = 33.34로 이 문제를 해결했는데 합산한 결과는 여전히 100입니다.

언급URL : https://stackoverflow.com/questions/22026226/is-there-an-algorithm-that-can-divide-a-number-into-three-parts-and-have-their-t

반응형