---
title: "원점에서 멀어지면 떨리는 이유"
description: "오픈월드에서 원점에서 수십 km 떨어지면 캐릭터와 카메라가 덜덜 떨립니다. float 는 큰 수일수록 표현할 수 있는 값 사이가 벌어져서, 작은 움직임이 반올림으로 사라지거나 부풀기 때문입니다. 세상을 원점 쪽으로 다시 옮겨서 막습니다."
author: "유니얼"
pubDate: 2026-11-05
category: "game-dev/math"
tags: ["Unity", "기초"]
canonical: https://blog.unialgames.com/posts/math-float-origin/
---
큰 맵을 만들어 원점에서 수십 km 떨어진 곳까지 가 보면, 가만히 서 있는 캐릭터가 덜덜 떨리고 카메라가 계단처럼 움직입니다.
천천히 걸으면 아예 움직이지 않다가, 조금 빨리 걸으면 이번에는 생각보다 빨리 갑니다.

유니티의 위치는 `float` 라는 숫자 형식에 담기고, **float 는 큰 수일수록 담을 수 있는 값 사이의 간격이 넓어집니다.**
1m 근처에서는 0.00000012m 단위까지 셀 수 있지만, 100,000m 근처에서는 0.0078m 단위로만 셀 수 있습니다. 그 사이의 값은 담을 수 없어서 가장 가까운 칸으로 반올림됩니다.

> **float 는 담을 수 있는 숫자 칸 수가 정해져 있어서, 값이 2 배 커질 때마다 칸의 간격도 2 배 넓어집니다.
> 100,000m 에서는 칸이 7.8mm 라, 한 프레임에 3mm 가는 움직임은 사라지고 5mm 는 7.8mm 로 부풉니다.
> 플레이어가 멀리 가면 세상 전체를 원점 쪽으로 옮겨 다시 원점 근처에서 계산합니다(floating origin).**

## 자릿수가 정해진 계산기

화면에 숫자를 **딱 7개**만 띄울 수 있는 계산기가 있다고 합시다. 소수점은 숫자 사이 아무 데나 찍을 수 있습니다.

| 넣은 값 | 7칸에 담긴 모습 | 소수점 아래 자리 | 바로 옆 값까지의 간격 |
| --- | --- | --- | --- |
| 1.234567 | 1.234567 | 6자리 | 0.000001 |
| 1,234.567 | 1234.567 | 3자리 | 0.001 |
| 123,456.7 | 123456.7 | 1자리 | 0.1 |
| 1,234,567 | 1234567 | 0자리 | 1 |

수가 커지면 앞자리가 칸을 먹어서, **소수점 아래에 남는 칸이 줄어듭니다.** 1 근처에서는 0.000001 까지 구분하던 계산기가 100만 근처에서는 1 단위로만 셉니다.
칸에 안 들어가는 값은 **반올림**합니다. 반올림은 가장 가까운 담을 수 있는 값으로 맞추는 것입니다. 123,456.78 은 8자리라 7칸에 안 들어가니, 가까운 123456.8 로 담깁니다. 0.02 가 버려졌습니다.

이 계산기가 담는 것을 둘로 나눠 볼 수 있습니다.

| 이름 | 무엇 | 123,456.7 이면 |
| --- | --- | --- |
| **유효 숫자** | 실제로 담긴 숫자들. 칸 수가 정해져 있음 | 1234567 (7자리) |
| **지수** | 소수점을 몇 자리 옮겼나. 10⁵ 는 10 을 다섯 번 곱한 100,000 | 1.234567 × 10⁵ 의 5 |

숫자 7개는 그대로 두고 지수만 바꿔 아주 작은 수부터 아주 큰 수까지 담는 방식을 **부동소수점**(소수점이 떠다닌다)이라고 부릅니다. float 가 이 방식입니다.

## float 는 2 배마다 칸이 2 배 넓어진다

실제 float 는 10진 숫자 대신 **0 과 1 로 된 2진 숫자**를 담습니다. 32비트(0 과 1 서른두 개) 안에 유효 숫자 24자리와 지수를 넣습니다.
2진수라서 칸 수가 같은 구간이 10 배 단위가 아니라 **2 배 단위**입니다. 1~2, 2~4, 4~8 … 처럼 2 배씩 커지는 구간마다 똑같이 **8,388,608 칸**(2를 23번 곱한 수)으로 나눕니다.
구간이 두 배로 길어지는데 칸 수는 같으니, **칸 하나의 폭이 두 배가 됩니다.**

칸이 8백만 개면 눈으로 볼 수 없으니, 한 구간을 **4칸**으로만 나누는 작은 float 를 그렸습니다.

<x-vec>
<script type="application/json">
{
  "label": "한 구간을 4칸으로만 나누는 작은 float",
  "view": [0, -1.5, 9, 2],
  "steps": [
    { "caption": "1 에서 2 사이를 4칸으로 나눕니다. 담을 수 있는 값은 1, 1.25, 1.5, 1.75 이고 간격은 1 ÷ 4 = 0.25 입니다. 1.1 같은 값은 담을 수 없습니다.", "items": [
      {"id": "p1", "type": "point", "at": [1, 0], "color": "accent"},
      {"id": "p1.25", "type": "point", "at": [1.25, 0], "color": "accent"},
      {"id": "p1.5", "type": "point", "at": [1.5, 0], "color": "accent"},
      {"id": "p1.75", "type": "point", "at": [1.75, 0], "color": "accent"},
      {"id": "t1", "type": "text", "at": [1.5, 1.2], "label": "간격 0.25", "color": "accent"} ] },
    { "caption": "2 에서 4 사이. 구간 길이는 2 로 두 배가 됐는데 칸은 그대로 4개라 2, 2.5, 3, 3.5. 간격도 2 ÷ 4 = 0.5 로 두 배입니다.", "items": [
      {"id": "p1", "type": "point", "at": [1, 0], "color": "muted"},
      {"id": "p1.25", "type": "point", "at": [1.25, 0], "color": "muted"},
      {"id": "p1.5", "type": "point", "at": [1.5, 0], "color": "muted"},
      {"id": "p1.75", "type": "point", "at": [1.75, 0], "color": "muted"},
      {"id": "p2", "type": "point", "at": [2, 0], "color": "accent"},
      {"id": "p2.5", "type": "point", "at": [2.5, 0], "color": "accent"},
      {"id": "p3", "type": "point", "at": [3, 0], "color": "accent"},
      {"id": "p3.5", "type": "point", "at": [3.5, 0], "color": "accent"},
      {"id": "t2", "type": "text", "at": [3.0, 1.2], "label": "간격 0.5", "color": "accent"} ] },
    { "caption": "4 에서 8 사이. 구간 길이 4 를 4칸으로 나눠 4, 5, 6, 7. 간격은 1 입니다. 수가 커질수록 담을 수 있는 값이 성겨집니다.", "items": [
      {"id": "p1", "type": "point", "at": [1, 0], "color": "muted"},
      {"id": "p1.25", "type": "point", "at": [1.25, 0], "color": "muted"},
      {"id": "p1.5", "type": "point", "at": [1.5, 0], "color": "muted"},
      {"id": "p1.75", "type": "point", "at": [1.75, 0], "color": "muted"},
      {"id": "p2", "type": "point", "at": [2, 0], "color": "muted"},
      {"id": "p2.5", "type": "point", "at": [2.5, 0], "color": "muted"},
      {"id": "p3", "type": "point", "at": [3, 0], "color": "muted"},
      {"id": "p3.5", "type": "point", "at": [3.5, 0], "color": "muted"},
      {"id": "p4", "type": "point", "at": [4, 0], "color": "accent"},
      {"id": "p5", "type": "point", "at": [5, 0], "color": "accent"},
      {"id": "p6", "type": "point", "at": [6, 0], "color": "accent"},
      {"id": "p7", "type": "point", "at": [7, 0], "color": "accent"},
      {"id": "t4", "type": "text", "at": [6.0, 1.2], "label": "간격 1", "color": "accent"},
      {"id": "p8", "type": "point", "at": [8, 0], "color": "muted", "label": "8", "labelAt": [8, -0.7]} ] }
  ]
}
</script>
</x-vec>

같은 일이 실제 float 에서 8,388,608 칸으로 일어납니다. **간격 = 구간 길이 ÷ 8,388,608** 입니다.

| 위치 (m) | 들어 있는 2 배 구간 | 간격 | 길이로 치면 |
| --- | --- | --- | --- |
| 1 | 1 ~ 2 | 1 ÷ 8,388,608 = 0.00000012 | 0.0001mm |
| 1,000 | 512 ~ 1,024 | 512 ÷ 8,388,608 = 0.000061 | 0.06mm |
| 10,000 | 8,192 ~ 16,384 | 8,192 ÷ 8,388,608 = 0.00098 | 1mm |
| 100,000 | 65,536 ~ 131,072 | 65,536 ÷ 8,388,608 = 0.0078 | **7.8mm** |
| 1,000,000 | 524,288 ~ 1,048,576 | 524,288 ÷ 8,388,608 = 0.0625 | **6cm** |

한 구간을 838만 칸으로 나누면 10진 숫자 7개쯤의 정밀도라, float 를 흔히 **유효 숫자 약 7자리**라고 부릅니다.
7칸 계산기와 숫자가 똑같지는 않지만(계산기는 10 배마다, float 는 2 배마다 칸이 넓어집니다), **수가 클수록 칸이 넓다**는 것은 같습니다.
1,000m 까지는 0.06mm 라 눈에 띌 일이 없지만, 100km 에서는 한 칸이 7.8mm, 1,000km 에서는 6cm 입니다.

## 작은 움직임이 사라지거나 부푼다

`position.x += 이동량` 을 하면 더한 결과가 **가장 가까운 칸으로 반올림**되어 저장됩니다.
이동량이 칸 간격의 절반보다 작으면 원래 자리로 반올림되어 **움직임이 사라지고**, 절반보다 크면 한 칸 통째로 가서 **부풉니다.**

100,000m 에서 칸은 7.8mm, 절반은 3.9mm 입니다. 한 프레임에 5mm 와 3mm 씩 가는 경우를 원점 근처와 비교합니다. 가로 한 칸이 1mm 이고, 경고색 점선이 100,000m 에서 float 가 가질 수 있는 값들입니다.

<x-vec>
<script type="application/json">
{
  "label": "한 프레임에 몇 mm 씩 갈 때, 실제로 저장되는 자리",
  "view": [-2, -1.5, 34, 2.5],
  "dwell": 1.8,
  "cases": [
    {
      "name": "원점 근처, 5mm",
      "steps": [
        { "caption": "원점 근처에서 출발. 한 프레임에 5mm 씩 갑니다.", "items": [
          { "id": "p", "type": "point", "at": [0, 0], "color": "accent", "label": "0mm", "labelAt": [0, 0.7] } ] },
        { "caption": "1 프레임. 5mm. 원점 근처는 칸이 아주 촘촘해서 더한 값이 그대로 저장됩니다.", "items": [
          { "id": "p", "type": "point", "at": [5, 0], "color": "accent", "label": "5mm", "labelAt": [5, 0.7] } ] },
        { "caption": "2 프레임. 10mm.", "items": [
          { "id": "p", "type": "point", "at": [10, 0], "color": "accent", "label": "10mm", "labelAt": [10, 0.7] } ] },
        { "caption": "4 프레임. 20mm. 고르게 갑니다.", "items": [
          { "id": "p", "type": "point", "at": [20, 0], "color": "accent", "label": "20mm", "labelAt": [20, 0.7] } ] }
      ]
    },
    {
      "name": "100km, 5mm",
      "steps": [
        { "caption": "100,000m 에서 출발. 경고색 점선이 float 가 저장할 수 있는 자리입니다. 7.8mm 마다 하나뿐입니다.", "items": [
          { "id": "g0", "type": "line", "from": [0, -1], "to": [0, 1.5], "color": "warn" },
          { "id": "g1", "type": "line", "from": [7.81, -1], "to": [7.81, 1.5], "color": "warn" },
          { "id": "g2", "type": "line", "from": [15.62, -1], "to": [15.62, 1.5], "color": "warn" },
          { "id": "g3", "type": "line", "from": [23.44, -1], "to": [23.44, 1.5], "color": "warn" },
          { "id": "g4", "type": "line", "from": [31.25, -1], "to": [31.25, 1.5], "color": "warn" },
          { "id": "p", "type": "point", "at": [0, 0], "color": "accent", "label": "+0", "labelAt": [0, 2] } ] },
        { "caption": "1 프레임. 5mm 를 더했지만 5mm 자리는 저장할 수 없습니다. 3.9mm 를 넘었으니 가까운 7.8mm 로 반올림됩니다.", "items": [
          { "id": "g0", "type": "line", "from": [0, -1], "to": [0, 1.5], "color": "warn" },
          { "id": "g1", "type": "line", "from": [7.81, -1], "to": [7.81, 1.5], "color": "warn" },
          { "id": "g2", "type": "line", "from": [15.62, -1], "to": [15.62, 1.5], "color": "warn" },
          { "id": "g3", "type": "line", "from": [23.44, -1], "to": [23.44, 1.5], "color": "warn" },
          { "id": "g4", "type": "line", "from": [31.25, -1], "to": [31.25, 1.5], "color": "warn" },
          { "id": "t", "type": "point", "at": [5, -0.6], "color": "muted", "label": "더한 값 5", "labelAt": [5, -1.2] },
          { "id": "p", "type": "point", "at": [7.81, 0], "color": "accent", "label": "+7.8", "labelAt": [7.81, 2] } ] },
        { "caption": "2 프레임. 7.8 + 5 = 12.8 이 가까운 15.6 으로. 매 프레임 한 칸씩 갑니다.", "items": [
          { "id": "g0", "type": "line", "from": [0, -1], "to": [0, 1.5], "color": "warn" },
          { "id": "g1", "type": "line", "from": [7.81, -1], "to": [7.81, 1.5], "color": "warn" },
          { "id": "g2", "type": "line", "from": [15.62, -1], "to": [15.62, 1.5], "color": "warn" },
          { "id": "g3", "type": "line", "from": [23.44, -1], "to": [23.44, 1.5], "color": "warn" },
          { "id": "g4", "type": "line", "from": [31.25, -1], "to": [31.25, 1.5], "color": "warn" },
          { "id": "t", "type": "point", "at": [12.81, -0.6], "color": "muted", "label": "더한 값 12.8", "labelAt": [12.81, -1.2] },
          { "id": "p", "type": "point", "at": [15.62, 0], "color": "accent", "label": "+15.6", "labelAt": [15.62, 2] } ] },
        { "caption": "4 프레임. 31.3mm. 원점 근처라면 20mm 였을 것이 56% 더 갔습니다. 걷는 속도가 위치에 따라 달라집니다.", "items": [
          { "id": "g0", "type": "line", "from": [0, -1], "to": [0, 1.5], "color": "warn" },
          { "id": "g1", "type": "line", "from": [7.81, -1], "to": [7.81, 1.5], "color": "warn" },
          { "id": "g2", "type": "line", "from": [15.62, -1], "to": [15.62, 1.5], "color": "warn" },
          { "id": "g3", "type": "line", "from": [23.44, -1], "to": [23.44, 1.5], "color": "warn" },
          { "id": "g4", "type": "line", "from": [31.25, -1], "to": [31.25, 1.5], "color": "warn" },
          { "id": "p", "type": "point", "at": [31.25, 0], "color": "warn", "label": "+31.3", "labelAt": [31.25, 2] } ] }
      ]
    },
    {
      "name": "100km, 3mm",
      "steps": [
        { "caption": "같은 100,000m. 이번엔 한 프레임에 3mm 씩.", "items": [
          { "id": "g0", "type": "line", "from": [0, -1], "to": [0, 1.5], "color": "warn" },
          { "id": "g1", "type": "line", "from": [7.81, -1], "to": [7.81, 1.5], "color": "warn" },
          { "id": "g2", "type": "line", "from": [15.62, -1], "to": [15.62, 1.5], "color": "warn" },
          { "id": "p", "type": "point", "at": [0, 0], "color": "accent", "label": "+0", "labelAt": [0, 2] } ] },
        { "caption": "1 프레임. 3mm 는 3.9mm 보다 작아 원래 자리 0 으로 반올림됩니다. 더했는데 안 움직였습니다.", "items": [
          { "id": "g0", "type": "line", "from": [0, -1], "to": [0, 1.5], "color": "warn" },
          { "id": "g1", "type": "line", "from": [7.81, -1], "to": [7.81, 1.5], "color": "warn" },
          { "id": "g2", "type": "line", "from": [15.62, -1], "to": [15.62, 1.5], "color": "warn" },
          { "id": "t", "type": "point", "at": [3, -0.6], "color": "muted", "label": "더한 값 3", "labelAt": [3, -1.2] },
          { "id": "p", "type": "point", "at": [0, 0], "color": "warn", "label": "+0", "labelAt": [0, 2] } ] },
        { "caption": "몇 프레임을 더해도 매번 0 + 3 = 3 이 0 으로 돌아옵니다. 천천히 걸으면 영원히 제자리입니다.", "items": [
          { "id": "g0", "type": "line", "from": [0, -1], "to": [0, 1.5], "color": "warn" },
          { "id": "g1", "type": "line", "from": [7.81, -1], "to": [7.81, 1.5], "color": "warn" },
          { "id": "g2", "type": "line", "from": [15.62, -1], "to": [15.62, 1.5], "color": "warn" },
          { "id": "t", "type": "point", "at": [3, -0.6], "color": "muted", "label": "더한 값 3", "labelAt": [3, -1.2] },
          { "id": "p", "type": "point", "at": [0, 0], "color": "warn", "label": "+0", "labelAt": [0, 2] } ] }
      ]
    }
  ]
}
</script>
</x-vec>

한 프레임 3mm 는 60fps(1초에 60장)에서 1초에 0.18m, 5mm 는 0.3m 입니다. 천천히 걷는 속도입니다.
**같은 코드가 원점 근처에서는 고르게, 100km 에서는 멈추거나 부풀게 움직입니다.** 프레임마다 이동량이 조금씩 달라 반올림 방향이 바뀌면, 그것이 떨림으로 보입니다.

## 위치만의 문제가 아니다

반올림은 위치를 쓰는 모든 계산에 따라 들어갑니다.

| 어디서 | 보이는 것 |
| --- | --- |
| 캐릭터 이동 | 천천히 걸으면 멈추고, 조금 빠르면 계단처럼 감 |
| 카메라 | 따라가는 카메라가 덜덜 떨림. 카메라와 대상이 따로 반올림되어 서로 어긋남 |
| 렌더링 | 메시의 꼭짓점 위치가 칸에 맞춰져 모양이 출렁임 |
| 물리 | 접촉점이 흔들려 가만히 놓인 물체가 떨리거나 미끄러짐 |
| 애니메이션 | 손발 위치가 칸에 맞춰져 관절이 떨림 |

**두 큰 수를 빼서 작은 차이를 구하는 계산**이 특히 약합니다.
100,000m 근처에 두 캐릭터가 실제로 5mm 떨어져 서 있다고 합시다. 둘의 위치는 7.8mm 칸으로 반올림되어 저장되니, 빼서 구한 거리는 0 이나 7.8mm 둘 중 하나만 나옵니다. 5mm 라는 답은 나올 수 없습니다.
카메라에서 물체까지의 방향, 두 캐릭터 사이의 거리 같은 값이 모두 이런 뺄셈입니다.

## 세상을 원점 쪽으로 옮긴다: floating origin

float 의 칸 수를 늘릴 수는 없으니, **계산하는 숫자를 작게 유지**합니다.
플레이어가 원점에서 일정 거리(예: 5km, 칸이 0.5mm 인 곳)를 벗어나면, 플레이어를 포함한 **모든 오브젝트를 같은 만큼 반대로 옮겨** 플레이어를 다시 원점 근처로 데려옵니다.
모두 같이 옮기니 서로의 상대 위치는 그대로이고, 플레이어 눈에는 아무 일도 일어나지 않습니다. 이 방식을 **floating origin** 이라고 부릅니다. 정해진 거리마다 한 번에 옮기는 것을 따로 origin shifting 이라고도 합니다.

플레이어가 x = 5,200 에 왔다면 모두를 x 로 −5,200 옮깁니다. 플레이어는 0 으로, 플레이어 앞 10m 에 있던 나무는 5,210 에서 10 으로 갑니다. 나무는 여전히 플레이어 앞 10m 입니다.

```csharp
public Transform player;
public float threshold = 5000f;   // 원점에서 5km 를 넘으면

// 세상이 원점에서 얼마나 옮겨졌는지. float 보다 칸이 훨씬 많은 double 로 들고 있는다
double worldX;
double worldZ;

void LateUpdate()
{
    Vector3 offset = player.position;
    offset.y = 0f;   // 보통 높이는 그대로 둔다

    if (offset.magnitude < threshold)
    {
        return;
    }

    // 루트 오브젝트(부모가 없는 것)를 전부 같은 만큼 반대로 옮긴다. 자식은 부모를 따라간다
    foreach (GameObject root in gameObject.scene.GetRootGameObjects())
    {
        root.transform.position -= offset;
    }

    // 옮긴 Transform 을 물리 엔진에도 바로 알린다
    Physics.SyncTransforms();

    worldX += offset.x;
    worldZ += offset.z;
}
```

`offset.magnitude` 는 원점에서 플레이어까지의 거리(화살표의 길이)입니다. `GetRootGameObjects` 는 이 스크립트가 있는 씬 하나만 돌려주니, 씬을 여러 개 띄운다면 씬마다 옮깁니다.
실제로 쓸 때는 챙길 것이 더 있습니다.

| 챙길 것 | 이유 |
| --- | --- |
| 파티클, 트레일 | 월드 공간에 남긴 흔적은 오브젝트와 따로 저장되어 있어 따로 옮겨야 함 |
| 물리 | 위치만 옮기고 속도는 그대로 둠. 물리 걸음 사이에 한 번에 옮김 |
| 카메라 | Cinemachine 이면 대상이 순간이동했다고 알려야(`OnTargetObjectWarped`) 카메라가 그 사이를 미끄러지지 않음 |
| 저장, 네트워크 | 화면 좌표가 아니라 `worldX`, `worldZ` 를 더한 진짜 좌표를 씀 |
| 내비메시, 정적 배칭 | 처음 자리에 맞춰 미리 만들어 둔 데이터라 옮기면 어긋남. 따로 다시 맞춰야 함 |

**double** 은 float 의 두 배인 64비트 숫자 형식입니다. 유효 숫자가 2진 53자리, 10진으로 약 15자리라 지구 둘레(약 40,000km)만 한 값에서도 칸 간격이 0.0000000075m 입니다.
유니티의 Transform 은 float 만 받으니, 게임 로직의 진짜 좌표는 double 로 따로 들고, 화면에 그릴 때만 원점 기준으로 빼서 float 로 넘기는 것이 큰 세계를 다루는 기본 방식입니다.

## 얼마나 멀면 문제가 되나

유니티 에디터도 위치의 x · y · z 중 하나가 100,000 을 넘으면 Transform Inspector 에 경고를 띄웁니다. "부동소수점 정밀도 한계 때문에 월드 좌표를 더 작은 범위로 가져오기를 권한다" 는 내용이고, 칸이 7.8mm 가 되는 자리입니다.

| 원점에서 | 칸 간격 | 대략 |
| --- | --- | --- |
| 1km 안 | 0.06mm 이하 | 걱정 없음 |
| 10km | 1mm | 가까이 본 카메라, 정밀한 애니메이션에서 보이기 시작 |
| 100km | 7.8mm | 걷기 · 카메라 떨림이 뚜렷함. 에디터 경고 |
| 1,000km | 6cm | 정상적인 플레이 불가 |

맵이 수 km 안이면 신경 쓰지 않아도 됩니다. 오픈월드, 비행, 우주처럼 수십 km 를 넘는 게임이면 처음부터 floating origin 을 계획에 넣습니다.
나중에 넣으면 위치를 저장하고 주고받는 모든 코드를 진짜 좌표로 고쳐야 해서 일이 커집니다.

## 정리

- 유니티의 위치는 float 입니다. float 는 유효 숫자 칸 수가 정해져 있고 지수로 소수점을 옮기는 부동소수점 형식입니다
- 2 배 구간마다 같은 8,388,608 칸으로 나누니, 값이 2 배가 될 때마다 칸의 간격도 2 배가 됩니다. 100km 에서 7.8mm, 1,000km 에서 6cm 입니다
- 더한 값은 가장 가까운 칸으로 반올림되어, 칸의 절반보다 작은 움직임은 사라지고 큰 움직임은 한 칸으로 부풉니다
- 큰 두 수를 빼서 작은 차이를 구하는 계산(방향, 거리)이 특히 거칠어집니다
- 플레이어가 멀어지면 모든 오브젝트를 같은 만큼 옮겨 원점 근처로 되돌리는 floating origin 으로 막습니다
- 진짜 좌표는 double 로 따로 들고, 그릴 때만 원점 기준으로 바꿔 float 로 씁니다